dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #38305
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19527: Refactor for quicker rules execution
------------------------------------------------------------
revno: 19527
committer: Markus Bekken <markus.bekken@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2015-07-01 08:24:47 +0200
message:
Refactor for quicker rules execution
modified:
dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.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/dataentry/dataentry-controller.js
dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.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/controllers.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js 2015-06-22 08:45:36 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js 2015-07-01 06:24:47 +0000
@@ -30,7 +30,8 @@
ModalService,
DialogService,
AuthorityService,
- TrackerRulesExecutionService) {
+ TrackerRulesExecutionService,
+ TrackerRulesFactory) {
//selected org unit
$scope.selectedOrgUnit = '';
$scope.treeLoaded = false;
@@ -106,6 +107,7 @@
$scope.selectedProgramStage = null;
$scope.programValidations = [];
$scope.programIndicators = [];
+ $scope.allProgramRules = [];
$scope.dhis2Events = [];
$scope.currentEvent = {};
$scope.currentEventOriginialValue = {};
@@ -193,12 +195,12 @@
}
$scope.newDhis2Event.eventDate = '';
- MetaDataFactory.getByProgram('programValidations', $scope.selectedProgram.id).then(function(pvs){
- $scope.programValidations = pvs;
- MetaDataFactory.getByProgram('programIndicators', $scope.selectedProgram.id).then(function(pis){
- $scope.programIndicators = pis;
+ MetaDataFactory.getByProgram('programIndicators', $scope.selectedProgram.id).then(function(pis){
+ $scope.programIndicators = pis;
+ TrackerRulesFactory.getRules($scope.selectedProgram.id).then(function(rules){
+ $scope.allProgramRules = rules;
$scope.loadEvents();
- });
+ });
});
});
}
@@ -304,7 +306,9 @@
if(!$scope.sortHeader.id){
$scope.sortEventGrid({name: $scope.selectedProgramStage.reportDateDescription ? $scope.selectedProgramStage.reportDateDescription : 'incident_date', id: 'event_date', type: 'date', compulsory: false, showFilter: false, show: true});
}
- }
+ }
+
+
$scope.eventFetched = true;
});
}
@@ -952,8 +956,14 @@
$scope.currentEvent.event = !$scope.currentEvent.event ? 'SINGLE_EVENT' : $scope.currentEvent.event;
$scope.eventsByStage = [];
$scope.eventsByStage[$scope.selectedProgramStage.id] = [$scope.currentEvent];
- TrackerRulesExecutionService.executeRules($scope.selectedProgram.id,$scope.currentEvent,$scope.eventsByStage,$scope.prStDes,null,false);
+ var evs = {all: [$scope.currentEvent], byStage: $scope.eventsByStage};
+
+ var flag = {debug: true, verbose: true};
+
+ //TrackerRulesExecutionService.executeRules($scope.selectedProgram.id,$scope.currentEvent,$scope.eventsByStage,$scope.prStDes,null,false);
+ TrackerRulesExecutionService.executeRules($scope.allProgramRules, $scope.currentEvent, evs, $scope.prStDes, $scope.selectedTei, $scope.selectedEnrollment, flag);
};
+
$scope.formatNumberResult = function(val){
return dhis2.validation.isNumber(val) ? val : '';
=== 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-22 07:04:03 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/services.js 2015-07-01 06:24:47 +0000
@@ -319,23 +319,9 @@
};
})
- /* Returns a function for getting rules for a specific program */
-.factory('TrackerRulesFactory', function($q,$rootScope,ECStorageService){
- return{
- getOldProgramStageRules :function(programUid, programstageUid) {
- var rules = this.getProgramRules(programUid);
-
- //Only keep the rules actually matching the program stage we are in, or rules with no program stage defined.
- var programStageRules = [];
- angular.forEach(rules, function(rule) {
- if(rule.programstage_uid == null || rule.programstage_uid == "" || rule.programstage_uid == programstageUid) {
- programStageRules.push(rule);
- }
- });
-
- return programStageRules;
- },
-
+/* Returns a function for getting rules for a specific program */
+.factory('TrackerRulesFactory', function($q,$rootScope,ECStorageService, MetaDataFactory){
+ return{
getProgramStageRules : function(programUid, programStageUid){
var def = $q.defer();
@@ -345,8 +331,9 @@
var programRulesArray = [];
//Loop through and add the rules belonging to this program and program stage
angular.forEach(rules, function(rule){
- if(rule.program.id == programUid) {
- if(!rule.programStage || !rule.programStage.id || rule.programStage.id == programStageUid) {
+ if(rule.program.id === programUid) {
+ if(!rule.programStage || !rule.programStage.id || rule.programStage.id === programStageUid) {
+ rule.actions = [];
programRulesArray.push(rule);
}
}
@@ -359,6 +346,92 @@
});
return def.promise;
+ },
+ getRules : function(programUid){
+ var def = $q.defer();
+ MetaDataFactory.getAll('constants').then(function(constants) {
+ MetaDataFactory.getByProgram('programIndicators',programUid).then(function(pis){
+ var variables = [];
+ var programRules = [];
+ angular.forEach(pis, function(pi){
+ var newAction = {
+ id:pi.id,
+ content:pi.displayDescription ? pi.displayDescription : pi.name,
+ data:pi.expression,
+ programRuleActionType:'DISPLAYKEYVALUEPAIR',
+ location:'indicators'
+ };
+ var newRule = {
+ name:pi.name,
+ id: pi.id,
+ 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:programUid
+ });
+ }
+ 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:programUid
+ });
+ }
+
+ };
+
+ angular.forEach(variablesInCondition, function(variableInCondition) {
+ pushDirectAddressedVariable(variableInCondition);
+ });
+
+ angular.forEach(variablesInData, function(variableInData) {
+ pushDirectAddressedVariable(variableInData);
+ });
+ });
+
+ var programIndicators = {rules:programRules, variables:variables};
+
+ MetaDataFactory.getByProgram('programValidations',programUid).then(function(programValidations){
+ MetaDataFactory.getByProgram('programRuleVariables',programUid).then(function(programVariables){
+ MetaDataFactory.getByProgram('programRules',programUid).then(function(prs){
+ var programRules = [];
+ angular.forEach(prs, function(rule){
+ rule.actions = [];
+ rule.programStageId = rule.programStage && rule.programStage.id ? rule.programStage.id : null;
+ programRules.push(rule);
+ });
+ def.resolve({constants: constants, programIndicators: programIndicators, programValidations: programValidations, programVariables: programVariables, programRules: programRules});
+ });
+ });
+ });
+ });
+ });
+ return def.promise;
}
};
})
=== 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-23 13:17:50 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js 2015-07-01 06:24:47 +0000
@@ -1,10 +1,10 @@
/* global angular, trackerCapture */
trackerCapture.controller('DataEntryController',
- function($rootScope,
+ function ($rootScope,
$scope,
- $modal,
- $filter,
+ $modal,
+ $filter,
$log,
$timeout,
Paginator,
@@ -18,10 +18,11 @@
OptionSetService,
ModalService,
CurrentSelection,
- TrackerRulesExecutionService,
- CustomFormService,
- PeriodService) {
-
+ TrackerRulesExecutionService,
+ CustomFormService,
+ PeriodService,
+ TrackerRulesFactory) {
+
//Data entry form
$scope.outerForm = {};
$scope.displayCustomForm = false;
@@ -34,49 +35,49 @@
//variable is set while looping through the program stages later.
$scope.stagesCanBeShownAsTable = false;
$scope.showHelpText = {};
- $scope.hiddenFields = {};
-
+ $scope.hiddenFields = {};
+
var userProfile = SessionStorageService.get('USER_PROFILE');
var storedBy = userProfile && userProfile.username ? userProfile.username : '';
-
+
var today = DateUtils.getToday();
$scope.invalidDate = false;
-
+
//note
$scope.note = '';
-
+
//event color legend
$scope.eventColors = [
- {color: 'alert-success', description: 'completed'},
- {color: 'alert-info', description: 'executed'},
- {color: 'alert-warning', description: 'ontime'},
- {color: 'alert-danger', description: 'overdue'},
- {color: 'alert-default', description: 'skipped'}
- ];
+ {color: 'alert-success ', description: 'completed'},
+ {color: 'alert-info ', description: 'executed'},
+ {color: 'alert-warning ', description: 'ontime'},
+ {color: 'alert-danger ', description: 'overdue'},
+ {color: 'alert-default ', description: 'skipped'}
+ ];
$scope.showEventColors = false;
-
+
//listen for rule effect changes
- $scope.$on('ruleeffectsupdated', function(event, args) {
- if($rootScope.ruleeffects[args.event]) {
+ $scope.$on('ruleeffectsupdated', function (event, args) {
+ if ($rootScope.ruleeffects[args.event]) {
//Establish which event was affected:
var affectedEvent = $scope.currentEvent;
//In most cases the updated effects apply to the current event. In case the affected event is not the current event, fetch the correct event to affect:
- if(args.event !== affectedEvent.event) {
- angular.forEach($scope.currentStageEvents, function(searchedEvent) {
- if(searchedEvent.event === args.event) {
+ if (args.event !== affectedEvent.event) {
+ angular.forEach($scope.currentStageEvents, function (searchedEvent) {
+ if (searchedEvent.event === args.event) {
affectedEvent = searchedEvent;
}
});
}
-
- angular.forEach($rootScope.ruleeffects[args.event], function(effect) {
- if( effect.dataElement ) {
+
+ angular.forEach($rootScope.ruleeffects[args.event], function (effect) {
+ if (effect.dataElement) {
//in the data entry controller we only care about the "hidefield" actions
- if(effect.action === "HIDEFIELD") {
- if(effect.dataElement) {
- if(effect.ineffect && affectedEvent[effect.dataElement.id]) {
+ 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) {
+ if (effect.content) {
//TODO: Alerts is going to be replaced with a proper display mecanism.
alert(effect.content);
}
@@ -87,7 +88,7 @@
//Blank out the value:
affectedEvent[effect.dataElement.id] = "";
- $scope.saveDatavalueForEvent($scope.prStDes[effect.dataElement.id],null,affectedEvent);
+ $scope.saveDatavalueForEvent($scope.prStDes[effect.dataElement.id], null, affectedEvent);
}
$scope.hiddenFields[effect.dataElement.id] = effect.ineffect;
@@ -100,196 +101,204 @@
});
}
});
-
+
//check if field is hidden
- $scope.isHidden = function(id) {
+ $scope.isHidden = function (id) {
//In case the field contains a value, we cant hide it.
//If we hid a field with a value, it would falsely seem the user was aware that the value was entered in the UI.
- if($scope.currentEvent[id]) {
- return false;
+ if ($scope.currentEvent[id]) {
+ return false;
}
else {
return $scope.hiddenFields[id];
}
- };
-
- $scope.executeRules = function() {
+ };
+
+ $scope.executeRules = function () {
+ var evs = {all: $scope.allEventsSorted, byStage: $scope.eventsByStageAsc};
+ var flag = {debug: true, verbose: true};
//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,$scope.selectedEnrollment,false);
- });
+ if ($scope.currentStage.displayEventsInTable) {
+ angular.forEach($scope.currentStageEvents, function (event) {
+ TrackerRulesExecutionService.executeRules($scope.allProgramRules, event, evs, $scope.prStDes, $scope.selectedTei, $scope.selectedEnrollment, flag);
+ });
} else {
- TrackerRulesExecutionService.executeRules($scope.selectedProgramId,$scope.currentEvent,$scope.eventsByStage,$scope.prStDes,$scope.selectedTei,$scope.selectedEnrollment,false);
+ TrackerRulesExecutionService.executeRules($scope.allProgramRules, $scope.currentEvent, evs, $scope.prStDes, $scope.selectedTei, $scope.selectedEnrollment, flag);
}
};
-
-
+
+
//listen for the selected items
- $scope.$on('dashboardWidgets', function() {
+ $scope.$on('dashboardWidgets', function () {
$scope.showDataEntryDiv = false;
$scope.showEventCreationDiv = false;
$scope.currentEvent = null;
$scope.currentStage = null;
$scope.currentStageEvents = null;
$scope.totalEvents = 0;
-
+
$scope.allowEventCreation = false;
- $scope.repeatableStages = [];
+ $scope.repeatableStages = [];
$scope.eventsByStage = [];
+ $scope.eventsByStageAsc = [];
$scope.programStages = [];
$rootScope.ruleeffects = {};
- $scope.prStDes = [];
-
- var selections = CurrentSelection.get();
+ $scope.prStDes = [];
+ $scope.allProgramRules = [];
+
+ var selections = CurrentSelection.get();
$scope.selectedOrgUnit = SessionStorageService.get('SELECTED_OU');
- $scope.selectedEntity = selections.tei;
- $scope.selectedProgram = selections.pr;
- $scope.selectedEnrollment = selections.selectedEnrollment;
+ $scope.selectedEntity = selections.tei;
+ $scope.selectedProgram = selections.pr;
+ $scope.selectedEnrollment = selections.selectedEnrollment;
$scope.optionSets = selections.optionSets;
-
- $scope.stagesById = [];
- if($scope.selectedOrgUnit && $scope.selectedProgram && $scope.selectedProgram.id && $scope.selectedEntity && $scope.selectedEnrollment && $scope.selectedEnrollment.enrollment){
- ProgramStageFactory.getByProgram($scope.selectedProgram).then(function(stages){
+
+ $scope.stagesById = [];
+ if ($scope.selectedOrgUnit && $scope.selectedProgram && $scope.selectedProgram.id && $scope.selectedEntity && $scope.selectedEnrollment && $scope.selectedEnrollment.enrollment) {
+ ProgramStageFactory.getByProgram($scope.selectedProgram).then(function (stages) {
$scope.programStages = stages;
- angular.forEach(stages, function(stage){
- if(stage.openAfterEnrollment){
+ angular.forEach(stages, function (stage) {
+ if (stage.openAfterEnrollment) {
$scope.currentStage = stage;
- }
-
- angular.forEach(stage.programStageDataElements, function(prStDe){
+ }
+
+ angular.forEach(stage.programStageDataElements, function (prStDe) {
$scope.prStDes[prStDe.dataElement.id] = prStDe;
});
-
+
$scope.stagesById[stage.id] = stage;
$scope.eventsByStage[stage.id] = [];
-
+
//If one of the stages has less than 7 data elements, allow sorting as table:
- if(stage.programStageDataElements.length < 7) {
+ if (stage.programStageDataElements.length < 7) {
$scope.stagesCanBeShownAsTable = true;
}
});
-
+
$scope.programStages = orderByFilter($scope.programStages, '-sortOrder').reverse();
- if(!$scope.currentStage){
+ if (!$scope.currentStage) {
$scope.currentStage = $scope.programStages[0];
}
- $scope.getEvents();
+
+ TrackerRulesFactory.getRules($scope.selectedProgram.id).then(function(rules){
+ $scope.allProgramRules = rules;
+ $scope.getEvents();
+ });
});
}
});
-
- $scope.getEvents = function(){
-
+
+ $scope.getEvents = function () {
+
var events = CurrentSelection.getSelectedTeiEvents();
events = $filter('filter')(events, {program: $scope.selectedProgram.id});
-
- if(angular.isObject(events)){
- angular.forEach(events, function(dhis2Event){
- if(dhis2Event.enrollment === $scope.selectedEnrollment.enrollment && dhis2Event.orgUnit){
- if(dhis2Event.notes){
+
+ if (angular.isObject(events)) {
+ angular.forEach(events, function (dhis2Event) {
+ if (dhis2Event.enrollment === $scope.selectedEnrollment.enrollment && dhis2Event.orgUnit) {
+ if (dhis2Event.notes) {
dhis2Event.notes = orderByFilter(dhis2Event.notes, '-storedDate');
- angular.forEach(dhis2Event.notes, function(note){
+ angular.forEach(dhis2Event.notes, function (note) {
note.storedDate = DateUtils.formatToHrsMins(note.storedDate);
});
}
var eventStage = $scope.stagesById[dhis2Event.programStage];
- if(angular.isObject(eventStage)){
- dhis2Event.name = eventStage.name;
+ if (angular.isObject(eventStage)) {
+ dhis2Event.name = eventStage.name;
dhis2Event.reportDateDescription = eventStage.reportDateDescription;
dhis2Event.dueDate = DateUtils.formatFromApiToUser(dhis2Event.dueDate);
dhis2Event.sortingDate = dhis2Event.dueDate;
- if(dhis2Event.eventDate){
+ if (dhis2Event.eventDate) {
dhis2Event.eventDate = DateUtils.formatFromApiToUser(dhis2Event.eventDate);
dhis2Event.sortingDate = dhis2Event.eventDate;
dhis2Event.editingNotAllowed = setEventEditing(dhis2Event, eventStage);
- }
+ }
dhis2Event.statusColor = EventUtils.getEventStatusColor(dhis2Event);
dhis2Event = EventUtils.processEvent(dhis2Event, eventStage, $scope.optionSets, $scope.prStDes);
$scope.eventsByStage[dhis2Event.programStage].push(dhis2Event);
- if($scope.currentStage && $scope.currentStage.id === dhis2Event.programStage){
- $scope.currentEvent = dhis2Event;
+ if ($scope.currentStage && $scope.currentStage.id === dhis2Event.programStage) {
+ $scope.currentEvent = dhis2Event;
}
}
}
});
-
+
sortEventsByStage(null);
- $scope.showDataEntry($scope.currentEvent, true);
+ $scope.showDataEntry($scope.currentEvent, true);
}
};
-
- var setEventEditing = function(dhis2Event, stage){
+
+ var setEventEditing = function (dhis2Event, stage) {
return dhis2Event.editingNotAllowed = dhis2Event.orgUnit !== $scope.selectedOrgUnit.id || (stage.blockEntryForm && dhis2Event.status === 'COMPLETED');
};
-
- $scope.enableRescheduling = function(){
+
+ $scope.enableRescheduling = function () {
$scope.schedulingEnabled = !$scope.schedulingEnabled;
};
-
- $scope.stageCanBeShownAsTable = function(stage) {
- if(stage.programStageDataElements && stage.programStageDataElements.length < 7) {
+
+ $scope.stageCanBeShownAsTable = function (stage) {
+ if (stage.programStageDataElements && stage.programStageDataElements.length < 7) {
return true;
}
return false;
};
-
- $scope.toggleEventsTableDisplay = function() {
+
+ $scope.toggleEventsTableDisplay = function () {
$scope.showEventsAsTables = !$scope.showEventsAsTables;
- angular.forEach($scope.programStages, function(stage){
- if(stage.programStageDataElements.length < 7) {
+ angular.forEach($scope.programStages, function (stage) {
+ if (stage.programStageDataElements.length < 7) {
stage.displayEventsInTable = $scope.showEventsAsTables;
- if($scope.currentStage === stage) {
+ if ($scope.currentStage === stage) {
$scope.getDataEntryForm();
}
}
});
};
-
- $scope.stageNeedsEvent = function(stage){
-
+
+ $scope.stageNeedsEvent = function (stage) {
+
//In case the event is a table, we sould always allow adding more events(rows)
- if(stage.displayEventsInTable) {
- return true;
- }
-
- if($scope.eventsByStage[stage.id].length < 1){
- return true;
- }
-
- if(stage.repeatable){
- for(var j=0; j<$scope.eventsByStage[stage.id].length; j++){
- if(!$scope.eventsByStage[stage.id][j].eventDate && $scope.eventsByStage[stage.id][j].status !== 'SKIPPED'){
+ if (stage.displayEventsInTable) {
+ return true;
+ }
+
+ if ($scope.eventsByStage[stage.id].length < 1) {
+ return true;
+ }
+
+ if (stage.repeatable) {
+ for (var j = 0; j < $scope.eventsByStage[stage.id].length; j++) {
+ if (!$scope.eventsByStage[stage.id][j].eventDate && $scope.eventsByStage[stage.id][j].status !== 'SKIPPED') {
return false;
}
}
- return true;
- }
- return false;
+ return true;
+ }
+ return false;
};
-
- $scope.showCreateEvent = function(stage){
-
+
+ $scope.showCreateEvent = function (stage) {
+
var dummyEvent = EventUtils.createDummyEvent($scope.eventsByStage[stage.id], $scope.selectedEntity, $scope.selectedProgram, stage, $scope.selectedOrgUnit, $scope.selectedEnrollment);
-
+
var modalInstance = $modal.open({
templateUrl: 'components/dataentry/new-event.html',
controller: 'EventCreationController',
resolve: {
- stagesById: function(){
+ stagesById: function () {
return $scope.stagesById;
},
- dummyEvent: function(){
+ dummyEvent: function () {
return dummyEvent;
},
- eventPeriods: function(){
+ eventPeriods: function () {
return $scope.eventPeriods;
},
- autoCreate: function() {
+ autoCreate: function () {
//In case the programstage is a table, autocreate
return stage.displayEventsInTable;
}
@@ -297,98 +306,109 @@
});
modalInstance.result.then(function (ev) {
- if(angular.isObject(ev)){
+ if (angular.isObject(ev)) {
var newEvent = ev;
newEvent.orgUnitName = dummyEvent.orgUnitName;
newEvent.name = dummyEvent.name;
newEvent.reportDateDescription = dummyEvent.reportDateDescription;
newEvent.sortingDate = ev.eventDate ? ev.eventDate : ev.dueDate,
- newEvent.statusColor = EventUtils.getEventStatusColor(ev);
+ newEvent.statusColor = EventUtils.getEventStatusColor(ev);
newEvent.eventDate = DateUtils.formatFromApiToUser(ev.eventDate);
- newEvent.dueDate = DateUtils.formatFromApiToUser(ev.dueDate);
+ newEvent.dueDate = DateUtils.formatFromApiToUser(ev.dueDate);
newEvent.enrollmentStatus = dummyEvent.enrollmentStatus;
-
- if(dummyEvent.coordinate){
+
+ if (dummyEvent.coordinate) {
newEvent.coordinate = {};
}
-
+
//Have to make sure the event is preprocessed - this does not happen unless "Dashboardwidgets" is invoked.
newEvent = EventUtils.processEvent(newEvent, stage, $scope.optionSets, $scope.prStDes);
-
-
+
+
$scope.eventsByStage[newEvent.programStage].push(newEvent);
$scope.currentEvent = newEvent;
sortEventsByStage('ADD');
$scope.currentEvent = null;
$scope.showDataEntry(newEvent, false);
- }
+ }
}, function () {
});
- };
-
- $scope.showDataEntry = function(event, rightAfterEnrollment){
- if(event){
-
- Paginator.setItemCount( $scope.eventsByStage[event.programStage].length );
- Paginator.setPage( $scope.eventsByStage[event.programStage].indexOf( event ) );
- Paginator.setPageCount( Paginator.getItemCount() );
- Paginator.setPageSize( 1 );
- Paginator.setToolBarDisplay( 5 );
-
- if($scope.currentEvent && !rightAfterEnrollment && $scope.currentEvent.event === event.event){
+ };
+
+ $scope.showDataEntry = function (event, rightAfterEnrollment) {
+ if (event) {
+
+ Paginator.setItemCount($scope.eventsByStage[event.programStage].length);
+ Paginator.setPage($scope.eventsByStage[event.programStage].indexOf(event));
+ Paginator.setPageCount(Paginator.getItemCount());
+ Paginator.setPageSize(1);
+ Paginator.setToolBarDisplay(5);
+
+ if ($scope.currentEvent && !rightAfterEnrollment && $scope.currentEvent.event === event.event) {
//clicked on the same stage, do toggling
$scope.currentEvent = null;
$scope.currentElement = {id: '', saved: false};
- $scope.showDataEntryDiv = !$scope.showDataEntryDiv;
+ $scope.showDataEntryDiv = !$scope.showDataEntryDiv;
}
- else{
- $scope.currentElement = {};
+ else {
+ $scope.currentElement = {};
$scope.currentEvent = event;
+
+ var index = -1;
+ for (var i = 0; i < $scope.eventsByStage[event.programStage].length && index === -1; i++) {
+ if ($scope.eventsByStage[event.programStage][i].event === event.event) {
+ index = i;
+ }
+ }
+ if(index !== -1){
+ $scope.currentEvent = $scope.eventsByStage[event.programStage][index];
+ }
+
$scope.showDataEntryDiv = true;
$scope.showEventCreationDiv = false;
- if($scope.currentEvent.notes){
- angular.forEach($scope.currentEvent.notes, function(note){
+ if ($scope.currentEvent.notes) {
+ angular.forEach($scope.currentEvent.notes, function (note) {
note.storedDate = DateUtils.formatToHrsMins(note.storedDate);
});
- if($scope.currentEvent.notes.length > 0 ){
+ if ($scope.currentEvent.notes.length > 0) {
$scope.currentEvent.notes = orderByFilter($scope.currentEvent.notes, '-storedDate');
}
}
-
+
$scope.getDataEntryForm();
- }
+ }
}
- };
-
- $scope.switchDataEntryForm = function(){
+ };
+
+ $scope.switchDataEntryForm = function () {
$scope.displayCustomForm = !$scope.displayCustomForm;
};
-
- $scope.getDataEntryForm = function(){
-
+
+ $scope.getDataEntryForm = function () {
+
$scope.currentStage = $scope.stagesById[$scope.currentEvent.programStage];
$scope.currentStageEvents = $scope.eventsByStage[$scope.currentEvent.programStage];
-
- angular.forEach($scope.currentStage.programStageSections, function(section){
+
+ angular.forEach($scope.currentStage.programStageSections, function (section) {
section.open = true;
});
$scope.customForm = CustomFormService.getForProgramStage($scope.currentStage, $scope.prStDes);
$scope.displayCustomForm = "default";
- if($scope.customForm){
+ if ($scope.customForm) {
$scope.displayCustomForm = "custom";
}
- else if($scope.currentStage.displayEventsInTable) {
+ else if ($scope.currentStage.displayEventsInTable) {
$scope.displayCustomForm = "table";
}
-
+
$scope.currentEventOriginal = angular.copy($scope.currentEvent);
$scope.currentStageEventsOriginal = angular.copy($scope.currentStageEvents);
-
+
var period = {event: $scope.currentEvent.event, stage: $scope.currentEvent.programStage, name: $scope.currentEvent.sortingDate};
$scope.currentPeriod[$scope.currentEvent.programStage] = period;
@@ -396,356 +416,327 @@
//Subsequent calls will be made from the "saveDataValue" function.
$scope.executeRules();
};
-
- function updateCurrentEventInStage(){
-
- var index = -1;
- for(var i=0; i<$scope.eventsByStage[$scope.currentEvent.programStage].length && index === -1; i++){
- if($scope.eventsByStage[$scope.currentEvent.programStage][i].event === $scope.currentEvent.event){
- index = i;
- }
- }
- if(index !== -1){
- $scope.eventsByStage[$scope.currentEvent.programStage].splice(index,1,$scope.currentEvent);
- }
-
- };
-
- $scope.saveDatavalue = function(prStDe,field){
- $scope.saveDatavalueForEvent(prStDe,field,$scope.currentEvent);
- };
-
- $scope.saveDatavalueForEvent = function(prStDe,field,eventToSave){
+
+ $scope.saveDatavalue = function (prStDe, field) {
+ $scope.saveDatavalueForEvent(prStDe, field, $scope.currentEvent);
+ };
+
+ $scope.saveDatavalueForEvent = function (prStDe, field, eventToSave) {
//Blank out the input-saved class on the last saved due date:
$scope.eventDateSaved = false;
-
+
//console.log('the field: ', field);
$scope.currentElement = {};
-
+
//check for input validity
//$scope.outerForm.submitted = true;
$scope.updateSuccess = false;
- if( field && field.$invalid ){
+ if (field && field.$invalid) {
//console.log('form is invalid...');
$scope.currentElement = {id: prStDe.dataElement.id, saved: false};
return false;
}
-
+
//input is valid
var value = eventToSave[prStDe.dataElement.id];
-
+
var oldValue = null;
angular.forEach($scope.currentStageEventsOriginal, function (eventOriginal) {
- if(eventOriginal.event === eventToSave.event) {
- oldValue = eventOriginal[prStDe.dataElement.id];
+ if (eventOriginal.event === eventToSave.event) {
+ oldValue = eventOriginal[prStDe.dataElement.id];
}
});
-
- if(oldValue !== value){
- if(value){
- if(prStDe.dataElement.type === 'date'){
+
+ if (oldValue !== value) {
+ if (value) {
+ if (prStDe.dataElement.type === 'date') {
value = DateUtils.formatFromUserToApi(value);
}
- if(prStDe.dataElement.optionSetValue){
- if(prStDe.dataElement.optionSet && $scope.optionSets[prStDe.dataElement.optionSet.id] && $scope.optionSets[prStDe.dataElement.optionSet.id].options ) {
+ if (prStDe.dataElement.optionSetValue) {
+ if (prStDe.dataElement.optionSet && $scope.optionSets[prStDe.dataElement.optionSet.id] && $scope.optionSets[prStDe.dataElement.optionSet.id].options) {
value = OptionSetService.getCode($scope.optionSets[prStDe.dataElement.optionSet.id].options, value);
- }
+ }
}
}
$scope.updateSuccess = false;
- $scope.currentElement = {id: prStDe.dataElement.id, event:eventToSave.event, saved: false};
-
- var ev = { event: eventToSave.event,
- orgUnit: eventToSave.orgUnit,
- program: eventToSave.program,
- programStage: eventToSave.programStage,
- status: eventToSave.status,
- trackedEntityInstance: eventToSave.trackedEntityInstance,
- dataValues: [
- {
- dataElement: prStDe.dataElement.id,
- value: value,
- providedElsewhere: eventToSave.providedElsewhere[prStDe.dataElement.id] ? true : false
- }
- ]
- };
- DHIS2EventFactory.updateForSingleValue(ev).then(function(response){
- updateCurrentEventInStage();
- sortEventsByStage('UPDATE');
-
+ $scope.currentElement = {id: prStDe.dataElement.id, event: eventToSave.event, saved: false};
+
+ var ev = {event: eventToSave.event,
+ orgUnit: eventToSave.orgUnit,
+ program: eventToSave.program,
+ programStage: eventToSave.programStage,
+ status: eventToSave.status,
+ trackedEntityInstance: eventToSave.trackedEntityInstance,
+ dataValues: [
+ {
+ dataElement: prStDe.dataElement.id,
+ value: value,
+ providedElsewhere: eventToSave.providedElsewhere[prStDe.dataElement.id] ? true : false
+ }
+ ]
+ };
+ DHIS2EventFactory.updateForSingleValue(ev).then(function (response) {
+
$scope.currentElement.saved = true;
-
+
$scope.currentEventOriginal = angular.copy($scope.currentEvent);
-
+
$scope.currentStageEventsOriginal = angular.copy($scope.currentStageEvents);
//Run rules on updated data:
- $scope.executeRules();
+ $scope.executeRules();
});
-
+
}
};
-
- $scope.saveDatavalueLocation = function(prStDe){
-
+
+ $scope.saveDatavalueLocation = function (prStDe) {
+
$scope.updateSuccess = false;
-
- if(!angular.isUndefined($scope.currentEvent.providedElsewhere[prStDe.dataElement.id])){
+
+ if (!angular.isUndefined($scope.currentEvent.providedElsewhere[prStDe.dataElement.id])) {
//currentEvent.providedElsewhere[prStDe.dataElement.id];
var value = $scope.currentEvent[prStDe.dataElement.id];
- var ev = { event: $scope.currentEvent.event,
- orgUnit: $scope.currentEvent.orgUnit,
- program: $scope.currentEvent.program,
- programStage: $scope.currentEvent.programStage,
- status: $scope.currentEvent.status,
- trackedEntityInstance: $scope.currentEvent.trackedEntityInstance,
- dataValues: [
- {
- dataElement: prStDe.dataElement.id,
- value: value,
- providedElsewhere: $scope.currentEvent.providedElsewhere[prStDe.dataElement.id] ? true : false
- }
- ]
- };
- DHIS2EventFactory.updateForSingleValue(ev).then(function(response){
- updateCurrentEventInStage();
- sortEventsByStage('UPDATE');
-
+ var ev = {event: $scope.currentEvent.event,
+ orgUnit: $scope.currentEvent.orgUnit,
+ program: $scope.currentEvent.program,
+ programStage: $scope.currentEvent.programStage,
+ status: $scope.currentEvent.status,
+ trackedEntityInstance: $scope.currentEvent.trackedEntityInstance,
+ dataValues: [
+ {
+ dataElement: prStDe.dataElement.id,
+ value: value,
+ providedElsewhere: $scope.currentEvent.providedElsewhere[prStDe.dataElement.id] ? true : false
+ }
+ ]
+ };
+ DHIS2EventFactory.updateForSingleValue(ev).then(function (response) {
$scope.updateSuccess = true;
});
}
};
-
+
$scope.saveEventDate = function () {
$scope.saveEventDateForEvent($scope.currentEvent);
};
-
- $scope.saveEventDateForEvent = function(eventToSave){
+
+ $scope.saveEventDateForEvent = function (eventToSave) {
$scope.eventDateSaved = false;
- if(eventToSave.eventDate === ''){
+ if (eventToSave.eventDate === '') {
$scope.invalidDate = eventToSave.event;
return false;
}
-
+
var rawDate = angular.copy(eventToSave.eventDate);
var convertedDate = DateUtils.format(eventToSave.eventDate);
-
- if(rawDate !== convertedDate){
+
+ if (rawDate !== convertedDate) {
$scope.invalidDate = true;
return false;
}
-
+
var e = {event: eventToSave.event,
- enrollment: eventToSave.enrollment,
- dueDate: DateUtils.formatFromUserToApi(eventToSave.dueDate),
- status: eventToSave.status === 'SCHEDULE' ? 'ACTIVE' : eventToSave.status,
- program: eventToSave.program,
- programStage: eventToSave.programStage,
- orgUnit: eventToSave.dataValues && eventToSave.length > 0 ? eventToSave.orgUnit : $scope.selectedOrgUnit.id,
- eventDate: DateUtils.formatFromUserToApi(eventToSave.eventDate),
- trackedEntityInstance: eventToSave.trackedEntityInstance
- };
+ enrollment: eventToSave.enrollment,
+ dueDate: DateUtils.formatFromUserToApi(eventToSave.dueDate),
+ status: eventToSave.status === 'SCHEDULE' ? 'ACTIVE' : eventToSave.status,
+ program: eventToSave.program,
+ programStage: eventToSave.programStage,
+ orgUnit: eventToSave.dataValues && eventToSave.length > 0 ? eventToSave.orgUnit : $scope.selectedOrgUnit.id,
+ eventDate: DateUtils.formatFromUserToApi(eventToSave.eventDate),
+ trackedEntityInstance: eventToSave.trackedEntityInstance
+ };
- DHIS2EventFactory.updateForEventDate(e).then(function(data){
+ DHIS2EventFactory.updateForEventDate(e).then(function (data) {
eventToSave.sortingDate = eventToSave.eventDate;
$scope.invalidDate = false;
$scope.eventDateSaved = eventToSave.event;
- eventToSave.statusColor = EventUtils.getEventStatusColor(eventToSave);
- sortEventsByStage();
- updateCurrentEventInStage();
+ eventToSave.statusColor = EventUtils.getEventStatusColor(eventToSave);
sortEventsByStage('UPDATE');
});
};
-
- $scope.saveDueDate = function(){
-
+
+ $scope.saveDueDate = function () {
+
$scope.dueDateSaved = false;
- if($scope.currentEvent.dueDate === ''){
+ if ($scope.currentEvent.dueDate === '') {
$scope.invalidDate = true;
return false;
}
-
+
var rawDate = angular.copy($scope.currentEvent.dueDate);
- var convertedDate = DateUtils.format($scope.currentEvent.dueDate);
+ var convertedDate = DateUtils.format($scope.currentEvent.dueDate);
- if(rawDate !== convertedDate){
+ if (rawDate !== convertedDate) {
$scope.invalidDate = true;
return false;
- }
-
+ }
+
var e = {event: $scope.currentEvent.event,
- enrollment: $scope.currentEvent.enrollment,
- dueDate: DateUtils.formatFromUserToApi($scope.currentEvent.dueDate),
- status: $scope.currentEvent.status,
- program: $scope.currentEvent.program,
- programStage: $scope.currentEvent.programStage,
- orgUnit: $scope.selectedOrgUnit.id,
- trackedEntityInstance: $scope.currentEvent.trackedEntityInstance
- };
-
- if($scope.currentStage.periodType){
+ enrollment: $scope.currentEvent.enrollment,
+ dueDate: DateUtils.formatFromUserToApi($scope.currentEvent.dueDate),
+ status: $scope.currentEvent.status,
+ program: $scope.currentEvent.program,
+ programStage: $scope.currentEvent.programStage,
+ orgUnit: $scope.selectedOrgUnit.id,
+ trackedEntityInstance: $scope.currentEvent.trackedEntityInstance
+ };
+
+ if ($scope.currentStage.periodType) {
e.eventDate = e.dueDate;
}
-
- if($scope.currentEvent.coordinate){
+
+ if ($scope.currentEvent.coordinate) {
e.coordinate = $scope.currentEvent.coordinate;
}
-
- DHIS2EventFactory.update(e).then(function(data){
+
+ DHIS2EventFactory.update(e).then(function (data) {
$scope.invalidDate = false;
$scope.dueDateSaved = true;
-
- if(e.eventDate && !$scope.currentEvent.eventDate && $scope.currentStage.periodType){
+
+ if (e.eventDate && !$scope.currentEvent.eventDate && $scope.currentStage.periodType) {
$scope.currentEvent.eventDate = $scope.currentEvent.dueDate;
}
-
- $scope.currentEvent.sortingDate = $scope.currentEvent.dueDate;
- $scope.currentEvent.statusColor = EventUtils.getEventStatusColor($scope.currentEvent);
+
+ $scope.currentEvent.sortingDate = $scope.currentEvent.dueDate;
+ $scope.currentEvent.statusColor = EventUtils.getEventStatusColor($scope.currentEvent);
$scope.schedulingEnabled = !$scope.schedulingEnabled;
-
- updateCurrentEventInStage();
sortEventsByStage('UPDATE');
});
-
+
};
-
- $scope.saveCoordinate = function(type){
-
- if(type === 'LAT' || type === 'LATLNG' ){
+
+ $scope.saveCoordinate = function (type) {
+
+ if (type === 'LAT' || type === 'LATLNG') {
$scope.latitudeSaved = false;
}
- if(type === 'LAT' || type === 'LATLNG'){
+ if (type === 'LAT' || type === 'LATLNG') {
$scope.longitudeSaved = false;
}
-
- if( (type === 'LAT' || type === 'LATLNG') && $scope.outerForm.latitude.$invalid ||
- (type === 'LNG' || type === 'LATLNG') && $scope.outerForm.longitude.$invalid ){//invalid coordinate
- return;
- }
-
- if( (type === 'LAT' || type === 'LATLNG') && $scope.currentEvent.coordinate.latitude === $scope.currentEventOriginal.coordinate.latitude ||
- (type === 'LNG' || type === 'LATLNG') && $scope.currentEvent.coordinate.longitude === $scope.currentEventOriginal.coordinate.longitude){//no change
- return;
- }
-
+
+ if ((type === 'LAT' || type === 'LATLNG') && $scope.outerForm.latitude.$invalid ||
+ (type === 'LNG' || type === 'LATLNG') && $scope.outerForm.longitude.$invalid) {//invalid coordinate
+ return;
+ }
+
+ if ((type === 'LAT' || type === 'LATLNG') && $scope.currentEvent.coordinate.latitude === $scope.currentEventOriginal.coordinate.latitude ||
+ (type === 'LNG' || type === 'LATLNG') && $scope.currentEvent.coordinate.longitude === $scope.currentEventOriginal.coordinate.longitude) {//no change
+ return;
+ }
+
//valid coordinate(s), proceed with the saving
var dhis2Event = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
-
- DHIS2EventFactory.update(dhis2Event).then(function(response){
+
+ DHIS2EventFactory.update(dhis2Event).then(function (response) {
$scope.currentEventOriginal = angular.copy($scope.currentEvent);
$scope.currentStageEventsOriginal = angular.copy($scope.currentStageEvents);
- if(type === 'LAT' || type === 'LATLNG' ){
+ if (type === 'LAT' || type === 'LATLNG') {
$scope.latitudeSaved = true;
}
- if(type === 'LAT' || type === 'LATLNG'){
+ if (type === 'LAT' || type === 'LATLNG') {
$scope.longitudeSaved = true;
}
-
- updateCurrentEventInStage();
- sortEventsByStage('UPDATE');
});
};
-
- $scope.addNote = function(){
- if(!angular.isUndefined($scope.note) && $scope.note !== ""){
+
+ $scope.addNote = function () {
+ if (!angular.isUndefined($scope.note) && $scope.note !== "") {
var newNote = {value: $scope.note};
- if(angular.isUndefined( $scope.currentEvent.notes) ){
+ if (angular.isUndefined($scope.currentEvent.notes)) {
$scope.currentEvent.notes = [{value: $scope.note, storedDate: today, storedBy: storedBy}];
}
- else{
- $scope.currentEvent.notes.splice(0,0,{value: $scope.note, storedDate: today, storedBy: storedBy});
+ else {
+ $scope.currentEvent.notes.splice(0, 0, {value: $scope.note, storedDate: today, storedBy: storedBy});
}
var e = {event: $scope.currentEvent.event,
- program: $scope.currentEvent.program,
- programStage: $scope.currentEvent.programStage,
- orgUnit: $scope.currentEvent.orgUnit,
- trackedEntityInstance: $scope.currentEvent.trackedEntityInstance,
- notes: [newNote]
- };
+ program: $scope.currentEvent.program,
+ programStage: $scope.currentEvent.programStage,
+ orgUnit: $scope.currentEvent.orgUnit,
+ trackedEntityInstance: $scope.currentEvent.trackedEntityInstance,
+ notes: [newNote]
+ };
- DHIS2EventFactory.updateForNote(e).then(function(data){
- $scope.note = '';
-
- updateCurrentEventInStage();
- sortEventsByStage('UPDATE');
+ DHIS2EventFactory.updateForNote(e).then(function (data) {
+ $scope.note = '';
});
- }
- };
-
- $scope.clearNote = function(){
- $scope.note = '';
- };
-
- $scope.getInputDueDateClass = function(event) {
- if(event.event === $scope.eventDateSaved) {
+ }
+ };
+
+ $scope.clearNote = function () {
+ $scope.note = '';
+ };
+
+ $scope.getInputDueDateClass = function (event) {
+ if (event.event === $scope.eventDateSaved) {
return 'input-success';
}
else {
return '';
}
-
+
};
-
+
/*$scope.getInputNotifcationClass = function(id, custom, event){
- if(!event) {
- event = $scope.currentEvent;
- }
- if($scope.currentElement.id && $scope.currentElement.event){
- if($scope.currentElement.saved && ($scope.currentElement.id === id && $scope.currentElement.event === event.event)){
-
- if(custom){
- return 'input-success';
- }
- return 'form-control input-success';
- }
- if(!$scope.currentElement.saved && ($scope.currentElement.id === id && $scope.currentElement.event === event.event)){
- if(custom){
- return 'input-error';
- }
- return 'form-control input-error';
- }
- }
- if(custom){
- return '';
- }
- return 'form-control';
- };*/
-
+ if(!event) {
+ event = $scope.currentEvent;
+ }
+ if($scope.currentElement.id && $scope.currentElement.event){
+ if($scope.currentElement.saved && ($scope.currentElement.id === id && $scope.currentElement.event === event.event)){
+
+ if(custom){
+ return 'input-success';
+ }
+ return 'form-control input-success';
+ }
+ if(!$scope.currentElement.saved && ($scope.currentElement.id === id && $scope.currentElement.event === event.event)){
+ if(custom){
+ return 'input-error';
+ }
+ return 'form-control input-error';
+ }
+ }
+ if(custom){
+ return '';
+ }
+ return 'form-control';
+ };*/
+
//Infinite Scroll
$scope.infiniteScroll = {};
$scope.infiniteScroll.optionsToAdd = 20;
$scope.infiniteScroll.currentOptions = 20;
-
- $scope.resetInfScroll = function() {
+
+ $scope.resetInfScroll = function () {
$scope.infiniteScroll.currentOptions = $scope.infiniteScroll.optionsToAdd;
};
-
- $scope.addMoreOptions = function(){
+
+ $scope.addMoreOptions = function () {
$scope.infiniteScroll.currentOptions += $scope.infiniteScroll.optionsToAdd;
- };
-
- $scope.getInputNotifcationClass = function(id, custom, event){
- if(!event) {
+ };
+
+ $scope.getInputNotifcationClass = function (id, custom, event) {
+ if (!event) {
event = $scope.currentEvent;
}
- if($scope.currentElement.id &&
- $scope.currentElement.event &&
+ if ($scope.currentElement.id &&
+ $scope.currentElement.event &&
$scope.currentElement.id === id &&
- $scope.currentElement.event === event.event){
- return $scope.currentElement.saved ? 'input-success; ' : 'input-error; ';
- }
-
+ $scope.currentElement.event === event.event) {
+ return $scope.currentElement.saved ? 'input-success; ' : 'input-error; ';
+ }
+
return '';
};
-
- var completeEnrollment = function(){
+
+ var completeEnrollment = function () {
var modalOptions = {
closeButtonText: 'cancel',
actionButtonText: 'complete',
@@ -753,26 +744,26 @@
bodyText: 'would_you_like_to_complete_enrollment'
};
- ModalService.showModal({}, modalOptions).then(function(result){
- EnrollmentService.complete($scope.selectedEnrollment).then(function(data){
- $scope.selectedEnrollment.status = 'COMPLETED';
+ ModalService.showModal({}, modalOptions).then(function (result) {
+ EnrollmentService.complete($scope.selectedEnrollment).then(function (data) {
+ $scope.selectedEnrollment.status = 'COMPLETED';
});
});
};
-
- $scope.completeIncompleteEvent = function(){
+
+ $scope.completeIncompleteEvent = function () {
var modalOptions;
- var dhis2Event = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
- if($scope.currentEvent.status === 'COMPLETED'){//activiate event
+ var dhis2Event = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
+ if ($scope.currentEvent.status === 'COMPLETED') {//activiate event
modalOptions = {
closeButtonText: 'cancel',
actionButtonText: 'incomplete',
headerText: 'incomplete',
bodyText: 'are_you_sure_to_incomplete_event'
};
- dhis2Event.status = 'ACTIVE';
+ dhis2Event.status = 'ACTIVE';
}
- else{//complete event
+ else {//complete event
modalOptions = {
closeButtonText: 'cancel',
actionButtonText: 'complete',
@@ -780,54 +771,52 @@
bodyText: 'are_you_sure_to_complete_event'
};
dhis2Event.status = 'COMPLETED';
- }
-
- ModalService.showModal({}, modalOptions).then(function(result){
-
- DHIS2EventFactory.update(dhis2Event).then(function(data){
-
- if($scope.currentEvent.status === 'COMPLETED'){//activiate event
- $scope.currentEvent.status = 'ACTIVE';
+ }
+
+ ModalService.showModal({}, modalOptions).then(function (result) {
+
+ DHIS2EventFactory.update(dhis2Event).then(function (data) {
+
+ if ($scope.currentEvent.status === 'COMPLETED') {//activiate event
+ $scope.currentEvent.status = 'ACTIVE';
}
- else{//complete event
+ else {//complete event
$scope.currentEvent.status = 'COMPLETED';
}
-
+
setStatusColor();
- updateCurrentEventInStage();
- sortEventsByStage('UPDATE');
-
+
setEventEditing($scope.currentEvent, $scope.currentStage);
-
- if($scope.currentEvent.status === 'COMPLETED'){
-
- if($scope.currentStage.remindCompleted){
+
+ if ($scope.currentEvent.status === 'COMPLETED') {
+
+ if ($scope.currentStage.remindCompleted) {
completeEnrollment($scope.currentStage);
}
- else{
- if($scope.currentStage.allowGenerateNextVisit){
+ else {
+ if ($scope.currentStage.allowGenerateNextVisit) {
$scope.showCreateEvent($scope.currentStage);
}
}
- }
+ }
});
});
};
-
- $scope.skipUnskipEvent = function(){
+
+ $scope.skipUnskipEvent = function () {
var modalOptions;
- var dhis2Event = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
+ var dhis2Event = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
- if($scope.currentEvent.status === 'SKIPPED'){//unskip event
+ if ($scope.currentEvent.status === 'SKIPPED') {//unskip event
modalOptions = {
closeButtonText: 'cancel',
actionButtonText: 'unskip',
headerText: 'unskip',
bodyText: 'are_you_sure_to_unskip_event'
};
- dhis2Event.status = 'ACTIVE';
+ dhis2Event.status = 'ACTIVE';
}
- else{//skip event
+ else {//skip event
modalOptions = {
closeButtonText: 'cancel',
actionButtonText: 'skip',
@@ -835,43 +824,42 @@
bodyText: 'are_you_sure_to_skip_event'
};
dhis2Event.status = 'SKIPPED';
- }
-
- ModalService.showModal({}, modalOptions).then(function(result){
-
- DHIS2EventFactory.update(dhis2Event).then(function(data){
-
- if($scope.currentEvent.status === 'SKIPPED'){//activiate event
- $scope.currentEvent.status = 'SCHEDULE';
+ }
+
+ ModalService.showModal({}, modalOptions).then(function (result) {
+
+ DHIS2EventFactory.update(dhis2Event).then(function (data) {
+
+ if ($scope.currentEvent.status === 'SKIPPED') {//activiate event
+ $scope.currentEvent.status = 'SCHEDULE';
}
- else{//complete event
+ else {//complete event
$scope.currentEvent.status = 'SKIPPED';
}
-
+
setStatusColor();
setEventEditing($scope.currentEvent, $scope.currentStage);
- updateCurrentEventInStage();
- sortEventsByStage('UPDATE');
});
});
};
-
- var setStatusColor = function(){
- var statusColor = EventUtils.getEventStatusColor($scope.currentEvent);
+
+ var setStatusColor = function () {
+ var statusColor = EventUtils.getEventStatusColor($scope.currentEvent);
var continueLoop = true;
- for(var i=0; i< $scope.eventsByStage[$scope.currentEvent.programStage].length && continueLoop; i++){
- if($scope.eventsByStage[$scope.currentEvent.programStage][i].event === $scope.currentEvent.event ){
+ for (var i = 0; i < $scope.eventsByStage[$scope.currentEvent.programStage].length && continueLoop; i++) {
+ if ($scope.eventsByStage[$scope.currentEvent.programStage][i].event === $scope.currentEvent.event) {
$scope.eventsByStage[$scope.currentEvent.programStage][i].statusColor = statusColor;
$scope.currentEvent.statusColor = statusColor;
continueLoop = false;
}
}
};
-
- $scope.validateEvent = function(){};
-
- $scope.deleteEvent = function(){
-
+
+ $scope.validateEvent = function () {
+ };
+
+ $scope.deleteEvent = function () {
+
var modalOptions = {
closeButtonText: 'cancel',
actionButtonText: 'delete',
@@ -879,142 +867,145 @@
bodyText: 'are_you_sure_to_delete_event'
};
- ModalService.showModal({}, modalOptions).then(function(result){
-
- DHIS2EventFactory.delete($scope.currentEvent).then(function(data){
-
+ ModalService.showModal({}, modalOptions).then(function (result) {
+
+ DHIS2EventFactory.delete($scope.currentEvent).then(function (data) {
+
var continueLoop = true, index = -1;
- for(var i=0; i< $scope.eventsByStage[$scope.currentEvent.programStage].length && continueLoop; i++){
- if($scope.eventsByStage[$scope.currentEvent.programStage][i].event === $scope.currentEvent.event ){
+ for (var i = 0; i < $scope.eventsByStage[$scope.currentEvent.programStage].length && continueLoop; i++) {
+ if ($scope.eventsByStage[$scope.currentEvent.programStage][i].event === $scope.currentEvent.event) {
$scope.eventsByStage[$scope.currentEvent.programStage][i] = $scope.currentEvent;
continueLoop = false;
index = i;
}
}
- $scope.eventsByStage[$scope.currentEvent.programStage].splice(index,1);
+ $scope.eventsByStage[$scope.currentEvent.programStage].splice(index, 1);
sortEventsByStage('REMOVE');
$scope.currentEvent = null;
});
});
};
-
- $scope.toggleLegend = function(){
+
+ $scope.toggleLegend = function () {
$scope.showEventColors = !$scope.showEventColors;
};
-
- $scope.getEventStyle = function(ev){
+
+ $scope.getEventStyle = function (ev) {
var style = EventUtils.getEventStatusColor(ev);
-
- if($scope.currentEvent && $scope.currentEvent.event === ev.event){
- style = style + ' ' + 'current-stage';
- }
+
+ if ($scope.currentEvent && $scope.currentEvent.event === ev.event) {
+ style = style + ' ' + ' current-stage';
+ }
return style;
};
-
- $scope.getColumnWidth = function(weight){
+
+ $scope.getColumnWidth = function (weight) {
var width = weight <= 1 ? 1 : weight;
- width = (width/$scope.totalEvents)*100;
+ width = (width / $scope.totalEvents) * 100;
return "width: " + width + '%';
};
-
- $scope.sortEventsByDate = function(dhis2Event){
- var d = dhis2Event.sortingDate;
- return DateUtils.getDate(d);
+
+ $scope.sortEventsByDate = function (dhis2Event) {
+ var d = dhis2Event.sortingDate;
+ return DateUtils.getDate(d);
};
-
- var sortEventsByStage = function(operation){
-
+
+ var sortEventsByStage = function (operation) {
+
$scope.eventFilteringRequired = false;
-
- for(var key in $scope.eventsByStage){
-
+
+ for (var key in $scope.eventsByStage) {
+
var stage = $scope.stagesById[key];
-
- if($scope.eventsByStage.hasOwnProperty(key) && stage){
-
- var sortedEvents = $filter('orderBy')($scope.eventsByStage[key], function(event) {
+
+ if ($scope.eventsByStage.hasOwnProperty(key) && stage) {
+
+ var sortedEvents = $filter('orderBy')($scope.eventsByStage[key], function (event) {
return DateUtils.getDate(event.sortingDate);
}, true);
-
+
$scope.eventsByStage[key] = sortedEvents;
-
+ $scope.eventsByStageAsc[key] = angular.copy(angular.copy(sortedEvents).reverse());
+
var periods = PeriodService.getPeriods(sortedEvents, stage, $scope.selectedEnrollment).occupiedPeriods;
-
+
$scope.eventPeriods[key] = periods;
- $scope.currentPeriod[key] = periods.length > 0 ? periods[0] : null;
- $scope.eventFilteringRequired = $scope.eventFilteringRequired ? $scope.eventFilteringRequired : periods.length > 1;
+ $scope.currentPeriod[key] = periods.length > 0 ? periods[0] : null;
+ $scope.eventFilteringRequired = $scope.eventFilteringRequired ? $scope.eventFilteringRequired : periods.length > 1;
}
}
- if(operation !== null){
-
- var evs = CurrentSelection.getSelectedTeiEvents();
-
- if( operation === 'ADD' ){
- var ev = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
- ev.enrollment = $scope.currentEvent.enrollment;
- ev.visited = $scope.currentEvent.visited;
- evs.push(ev);
- }
- if( operation === 'UPDATE' ){
- var ev = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
- ev.enrollment = $scope.currentEvent.enrollment;
- ev.visited = $scope.currentEvent.visited;
- var index = -1;
- for(var i=0; i<evs.length && index === -1; i++){
- if(evs[i].event === $scope.currentEvent.event){
- index = i;
- }
- }
- if(index !== -1){
- evs[index] = ev;
- }
- }
- if( operation === 'REMOVE' ){
- var index = -1;
- for(var i=0; i<evs.length && index === -1; i++){
- if(evs[i].event === $scope.currentEvent.event){
- index = i;
- }
- }
- if(index !== -1){
- evs.splice(index,1);
- }
- }
-
- CurrentSelection.setSelectedTeiEvents( evs );
-
- $timeout(function() {
- $rootScope.$broadcast('tei-report-widget', {});
+ $scope.allEventsSorted = CurrentSelection.getSelectedTeiEvents();
+
+ if (operation) {
+
+ if (operation === 'ADD') {
+ var ev = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
+ ev.enrollment = $scope.currentEvent.enrollment;
+ ev.visited = $scope.currentEvent.visited;
+ $scope.allEventsSorted.push(ev);
+ }
+ if (operation === 'UPDATE') {
+ var ev = EventUtils.reconstruct($scope.currentEvent, $scope.currentStage, $scope.optionSets);
+ ev.enrollment = $scope.currentEvent.enrollment;
+ ev.visited = $scope.currentEvent.visited;
+ var index = -1;
+ for (var i = 0; i < $scope.allEventsSorted.length && index === -1; i++) {
+ if ($scope.allEventsSorted[i].event === $scope.currentEvent.event) {
+ index = i;
+ }
+ }
+ if (index !== -1) {
+ $scope.allEventsSorted[index] = ev;
+ }
+ }
+ if (operation === 'REMOVE') {
+ var index = -1;
+ for (var i = 0; i < $scope.allEventsSorted.length && index === -1; i++) {
+ if ($scope.allEventsSorted[i].event === $scope.currentEvent.event) {
+ index = i;
+ }
+ }
+ if (index !== -1) {
+ $scope.allEventsSorted.splice(index, 1);
+ }
+ }
+
+ CurrentSelection.setSelectedTeiEvents($scope.allEventsSorted);
+
+ $timeout(function () {
+ $rootScope.$broadcast('tei-report-widget', {});
}, 100);
- }
+ }
+
+ $scope.allEventsSorted = orderByFilter($scope.allEventsSorted, '-sortingDate').reverse();
};
-
- $scope.showLastEventInStage = function(stageId){
- var ev = $scope.eventsByStage[stageId][$scope.eventsByStage[stageId].length-1];
+
+ $scope.showLastEventInStage = function (stageId) {
+ var ev = $scope.eventsByStage[stageId][$scope.eventsByStage[stageId].length - 1];
$scope.showDataEntryForEvent(ev);
};
-
- $scope.showDataEntryForEvent = function(event){
-
+
+ $scope.showDataEntryForEvent = function (event) {
+
var period = {event: event.event, stage: event.programStage, name: event.sortingDate};
$scope.currentPeriod[event.programStage] = period;
-
+
var event = null;
- for(var i=0; i<$scope.eventsByStage[period.stage].length; i++){
- if($scope.eventsByStage[period.stage][i].event === period.event){
+ for (var i = 0; i < $scope.eventsByStage[period.stage].length; i++) {
+ if ($scope.eventsByStage[period.stage][i].event === period.event) {
event = $scope.eventsByStage[period.stage][i];
break;
}
}
-
- if(event){
+
+ if (event) {
$scope.showDataEntry(event, false);
}
-
+
};
-
- $scope.showMap = function(event){
+
+ $scope.showMap = function (event) {
var modalInstance = $modal.open({
templateUrl: '../dhis-web-commons/angular-forms/map.html',
controller: 'MapController',
@@ -1027,105 +1018,105 @@
});
modalInstance.result.then(function (location) {
- if(angular.isObject(location)){
+ if (angular.isObject(location)) {
event.coordinate.latitude = location.lat;
- event.coordinate.longitude = location.lng;
+ event.coordinate.longitude = location.lng;
$scope.saveCoordinate('LATLNG');
}
}, function () {
});
};
-
- $scope.interacted = function(field) {
+
+ $scope.interacted = function (field) {
var status = false;
- if(field){
+ if (field) {
status = $scope.outerForm.submitted || field.$dirty;
- }
- return status;
+ }
+ return status;
};
-
+
})
-.controller('EventCreationController',
- function($scope,
- $modalInstance,
- DateUtils,
- DHIS2EventFactory,
- DialogService,
- stagesById,
- dummyEvent,
- eventPeriods,
- autoCreate){
+.controller('EventCreationController',
+ function ($scope,
+ $modalInstance,
+ DateUtils,
+ DHIS2EventFactory,
+ DialogService,
+ stagesById,
+ dummyEvent,
+ eventPeriods,
+ autoCreate) {
$scope.stagesById = stagesById;
$scope.programStageId = dummyEvent.programStage;
$scope.eventPeriods = eventPeriods;
- $scope.selectedStage = $scope.stagesById[dummyEvent.programStage];
-
+ $scope.selectedStage = $scope.stagesById[dummyEvent.programStage];
+
$scope.dhis2Event = {eventDate: '', dueDate: dummyEvent.dueDate, reportDateDescription: dummyEvent.reportDateDescription, name: dummyEvent.name, invalid: true};
-
- if($scope.selectedStage.periodType){
+
+ if ($scope.selectedStage.periodType) {
$scope.dhis2Event.eventDate = dummyEvent.dueDate;
$scope.dhis2Event.periodName = dummyEvent.periodName;
$scope.dhis2Event.periods = dummyEvent.periods;
$scope.dhis2Event.selectedPeriod = dummyEvent.periods[0];
}
-
+
$scope.dueDateInvalid = false;
$scope.eventDateInvalid = false;
-
+
//watch for changes in due/event-date
- $scope.$watchCollection('[dhis2Event.dueDate, dhis2Event.eventDate]', function() {
- if(angular.isObject($scope.dhis2Event)){
- if(!$scope.dhis2Event.dueDate){
+ $scope.$watchCollection('[dhis2Event.dueDate, dhis2Event.eventDate]', function () {
+ if (angular.isObject($scope.dhis2Event)) {
+ if (!$scope.dhis2Event.dueDate) {
$scope.dueDateInvalid = true;
return;
}
-
- if($scope.dhis2Event.dueDate){
+
+ if ($scope.dhis2Event.dueDate) {
var rDueDate = $scope.dhis2Event.dueDate;
- var cDueDate = DateUtils.format($scope.dhis2Event.dueDate);
+ var cDueDate = DateUtils.format($scope.dhis2Event.dueDate);
$scope.dueDateInvalid = rDueDate !== cDueDate;
}
-
- if($scope.dhis2Event.eventDate){
+
+ if ($scope.dhis2Event.eventDate) {
var rEventDate = $scope.dhis2Event.eventDate;
var cEventDate = DateUtils.format($scope.dhis2Event.eventDate);
$scope.eventDateInvalid = rEventDate !== cEventDate;
}
}
});
-
+
$scope.save = function () {
//check for form validity
- if($scope.dueDateInvalid || $scope.eventDateInvalid){
+ if ($scope.dueDateInvalid || $scope.eventDateInvalid) {
return false;
}
-
- if($scope.selectedStage.periodType){
+
+ if ($scope.selectedStage.periodType) {
$scope.dhis2Event.eventDate = $scope.dhis2Event.selectedPeriod.endDate;
$scope.dhis2Event.dueDate = $scope.dhis2Event.selectedPeriod.endDate;
- }
-
+ }
+
var eventDate = DateUtils.formatFromUserToApi($scope.dhis2Event.eventDate);
var dueDate = DateUtils.formatFromUserToApi($scope.dhis2Event.dueDate);
var newEvents = {events: []};
var newEvent = {
- trackedEntityInstance: dummyEvent.trackedEntityInstance,
- program: dummyEvent.program,
- programStage: dummyEvent.programStage,
- enrollment: dummyEvent.enrollment,
- orgUnit: dummyEvent.orgUnit,
- dueDate: dueDate,
- eventDate: eventDate,
- notes: [],
- dataValues: [],
- status: 'ACTIVE'
- };
-
+ trackedEntityInstance: dummyEvent.trackedEntityInstance,
+ program: dummyEvent.program,
+ programStage: dummyEvent.programStage,
+ enrollment: dummyEvent.enrollment,
+ orgUnit: dummyEvent.orgUnit,
+ dueDate: dueDate,
+ eventDate: eventDate,
+ notes: [],
+ dataValues: [],
+ status: 'ACTIVE'
+ };
+
newEvent.status = newEvent.eventDate ? 'ACTIVE' : 'SCHEDULE';
-
+
newEvents.events.push(newEvent);
- DHIS2EventFactory.create(newEvents).then(function(data){
+ DHIS2EventFactory.create(newEvents).then(function (data) {
if (data.importSummaries[0].status === 'ERROR') {
var dialogOptions = {
headerText: 'event_creation_error',
@@ -1135,20 +1126,21 @@
DialogService.showDialog({}, dialogOptions);
}
else {
- newEvent.event = data.importSummaries[0].reference;
+ newEvent.event = data.importSummaries[0].reference;
$modalInstance.close(newEvent);
}
});
-
-
+
+
};
-
+
//If the caller wants to create right away, go ahead and save.
- if(autoCreate) {
+ if (autoCreate) {
$scope.save();
- };
-
- $scope.cancel = function(){
+ }
+ ;
+
+ $scope.cancel = function () {
$modalInstance.close();
- };
+ };
});
=== 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-24 06:56:16 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js 2015-07-01 06:24:47 +0000
@@ -666,7 +666,7 @@
},
search: function(ouId, ouMode, queryUrl, programUrl, attributeUrl, pager, paging) {
- var url = '../api/trackedEntityInstances.json?ou=' + ouId + '&ouMode='+ ouMode;
+ var url = '../api/trackedEntityInstances/query.json?ou=' + ouId + '&ouMode='+ ouMode;
if(queryUrl){
url = url + '&'+ queryUrl;
@@ -1098,23 +1098,9 @@
};
})
- /* Returns a function for getting rules for a specific program */
-.factory('TrackerRulesFactory', function($q,$rootScope,TCStorageService){
- return{
- getOldProgramStageRules :function(programUid, programstageUid) {
- var rules = this.getProgramRules(programUid);
-
- //Only keep the rules actually matching the program stage we are in, or rules with no program stage defined.
- var programStageRules = [];
- angular.forEach(rules, function(rule) {
- if(rule.programstage_uid == null || rule.programstage_uid == "" || rule.programstage_uid == programstageUid) {
- programStageRules.push(rule);
- }
- });
-
- return programStageRules;
- },
-
+/* Returns a function for getting rules for a specific program */
+.factory('TrackerRulesFactory', function($q,$rootScope,TCStorageService, MetaDataFactory){
+ return{
getProgramStageRules : function(programUid, programStageUid){
var def = $q.defer();
@@ -1124,8 +1110,8 @@
var programRulesArray = [];
//Loop through and add the rules belonging to this program and program stage
angular.forEach(rules, function(rule){
- if(rule.program.id == programUid) {
- if(!rule.programStage || !rule.programStage.id || rule.programStage.id == programStageUid) {
+ if(rule.program.id === programUid) {
+ if(!rule.programStage || !rule.programStage.id || rule.programStage.id === programStageUid) {
rule.actions = [];
programRulesArray.push(rule);
}
@@ -1139,74 +1125,96 @@
});
return def.promise;
+ },
+ getRules : function(programUid){
+ var def = $q.defer();
+ MetaDataFactory.getAll('constants').then(function(constants) {
+ MetaDataFactory.getByProgram('programIndicators',programUid).then(function(pis){
+ var variables = [];
+ var programRules = [];
+ angular.forEach(pis, function(pi){
+ var newAction = {
+ id:pi.id,
+ content:pi.displayDescription ? pi.displayDescription : pi.name,
+ data:pi.expression,
+ programRuleActionType:'DISPLAYKEYVALUEPAIR',
+ location:'indicators'
+ };
+ var newRule = {
+ name:pi.name,
+ id: pi.id,
+ 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:programUid
+ });
+ }
+ 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:programUid
+ });
+ }
+
+ };
+
+ angular.forEach(variablesInCondition, function(variableInCondition) {
+ pushDirectAddressedVariable(variableInCondition);
+ });
+
+ angular.forEach(variablesInData, function(variableInData) {
+ pushDirectAddressedVariable(variableInData);
+ });
+ });
+
+ var programIndicators = {rules:programRules, variables:variables};
+
+ MetaDataFactory.getByProgram('programValidations',programUid).then(function(programValidations){
+ MetaDataFactory.getByProgram('programRuleVariables',programUid).then(function(programVariables){
+ MetaDataFactory.getByProgram('programRules',programUid).then(function(prs){
+ var programRules = [];
+ angular.forEach(prs, function(rule){
+ rule.actions = [];
+ rule.programStageId = rule.programStage && rule.programStage.id ? rule.programStage.id : null;
+ programRules.push(rule);
+ });
+ def.resolve({constants: constants, programIndicators: programIndicators, programValidations: programValidations, programVariables: programVariables, programRules: programRules});
+ });
+ });
+ });
+ });
+ });
+ return def.promise;
}
};
})
-/* Returns user defined variable names and their corresponding UIDs and types for a specific program */
-.factory('TrackerRuleVariableFactory', function($rootScope, $q, TCStorageService){
- return{
- getProgramRuleVariables : function(programUid){
- var def = $q.defer();
-
- TCStorageService.currentStore.open().done(function(){
-
- TCStorageService.currentStore.getAll('programRuleVariables').done(function(variables){
-
- //The array will ultimately be returned to the caller.
- var programRuleVariablesArray = [];
- //Loop through and add the variables belonging to this program
- angular.forEach(variables, function(variable){
- if(variable.program.id == programUid) {
- programRuleVariablesArray.push(variable);
- }
- });
-
- $rootScope.$apply(function(){
- def.resolve(programRuleVariablesArray);
- });
- });
- });
-
- return def.promise;
- }
- };
-})
-
-/* Returns user defined variable names and their corresponding UIDs and types for a specific program */
-.factory('TrackerWidgetsConfigurationFactory', function(){
- return{
- getWidgetConfiguration : function(programUid){
- //If no config exists, return default config
-
- return [
- {title: 'Details', type: 'rulebound', code:"det", show: true, expand: true, horizontalplacement:"left", index:0},
- {title: 'enrollment', type:'enrollment', show: false, expand: true, horizontalplacement:"left", index:1},
- {title: 'dataentry', type: 'dataentry', show: true, expand: true, horizontalplacement:"left", index:2},
- {title: 'report', type: 'report', show: false, expand: true, horizontalplacement:"left", index:3},
- {title: 'current_selections', type: 'current_selections', show: false, expand: true, horizontalplacement:"right", index:0},
- {title: 'profile', type: 'profile', show: false, expand: true, horizontalplacement:"right", index:1},
- {title: 'Conditions/Complications', type:'rulebound', code:"con", show: true, expand: true, horizontalplacement:"right", index:2},
- {title: 'relationships', type: 'relationships', show: false, expand: true, horizontalplacement:"right", index:3},
- {title: 'notes', type: 'notes', show: true, expand: true, horizontalplacement:"right", index:4},
- {title: 'Summary', type: 'rulebound', code:"sum", show: true, expand: true, horizontalplacement:"left", index:4}
- ];
- },
- getDefaultWidgetConfiguration: function() {
- return [
- {title: 'enrollment', type:'enrollment', show: true, expand: true, horizontalplacement:"left", index:0},
- {title: 'dataentry', type: 'dataentry', show: true, expand: true, horizontalplacement:"left", index:1},
- {title: 'report', type: 'report', show: true, expand: true, horizontalplacement:"left", index:2},
- {title: 'current_selections', type: 'current_selections', show: false, expand: true, horizontalplacement:"right", index:0},
- {title: 'profile', type: 'profile', show: true, expand: true, horizontalplacement:"right", index:1},
- {title: 'relationships', type: 'relationships', show: true, expand: true, horizontalplacement:"right", index:2},
- {title: 'notes', type: 'notes', show: true, expand: true, horizontalplacement:"right", index:3}
- ];
- }
- };
-
-})
-
.service('EntityQueryFactory', function(OperatorFactory, DateUtils){
this.getAttributesQuery = function(attributes, enrollment){
=== 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-23 19:48:46 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js 2015-07-01 06:24:47 +0000
@@ -1,4 +1,6 @@
/* Pagination service */
+/* global angular, dhis2, moment */
+
var d2Services = angular.module('d2Services', ['ngResource'])
/* Factory for loading translation strings */
@@ -712,589 +714,510 @@
})
/* service for building variables based on the data in users fields */
-.service('VariableService', function($rootScope,$q,TrackerRuleVariableFactory,DateUtils,CalendarService,MetaDataFactory,$filter,orderByFilter,$log){
- return {
- getVariables: function(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity, variablesFromIndicators, selectedEnrollment) {
- var thePromisedVariables = $q.defer();
+.service('VariableService', function(DateUtils,$filter,$log){
+
+ var pushVariable = function(variables, 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);
+
+ //Append single quotation marks in case the variable is of text or date type:
+ if(variableType === 'string' || variableType === 'date') {
+ variableValue = "'" + variableValue + "'";
+ }
+ else if(variableType === 'bool' || variableType === 'trueOnly') {
+ if(eval(variableValue)) {
+ variableValue = true;
+ }
+ else {
+ variableValue = false;
+ }
+ }
+ else if(variableType === "int" || variableType === "number") {
+ variableValue = Number(variableValue);
+ }
+ else{
+ $log.warn("unknown datatype:" + variableType);
+ }
+
+ variables[variablename] = {
+ variableValue:variableValue,
+ variableType:variableType,
+ hasValue:variablefound,
+ variablePrefix:variablePrefix
+ };
+ return variables;
+ };
+
+ return {
+ processVariables: function(variables, variablename, variableValue, variableType, variablefound, variablePrefix) {
+ return pushVariable(variables, variablename, variableValue, variableType, variablefound, variablePrefix);
+ },
+ getVariables: function(allProgramRules, executingEvent, evs, allDes, selectedEntity, selectedEnrollment) {
var variables = {};
- 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);
-
- //Append single quotation marks in case the variable is of text type:
- if(variableType === 'string') {
- variableValue = "'" + variableValue + "'";
- }
- else if(variableType === 'date') {
- variableValue = "'" + variableValue + "'";
- }
- else if(variableType === 'bool' || variableType === 'trueOnly') {
- if(eval(variableValue)) {
- variableValue = true;
+ var programVariables = allProgramRules.programVariables;
+
+ programVariables = programVariables.concat(allProgramRules.programIndicators.variables);
+
+ angular.forEach(programVariables, function(programVariable) {
+ var dataElementId = programVariable.dataElement;
+ if(programVariable.dataElement && programVariable.dataElement.id) {
+ dataElementId = programVariable.dataElement.id;
+ }
+
+ var programStageId = programVariable.programStage;
+ if(programVariable.programStage && programVariable.programStage.id) {
+ programStageId = programVariable.programStage.id;
+ }
+
+ var valueFound = false;
+ if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE"){
+ if(programStageId) {
+ angular.forEach(evs.byStage[programStageId], function(event) {
+ if(angular.isDefined(event[dataElementId])
+ && event[dataElementId] !== null ){
+ valueFound = true;
+ variables = pushVariable(variables, 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(evs.all, function(event) {
+ if(angular.isDefined(event[dataElementId])
+ && event[dataElementId] !== null ){
+ valueFound = true;
+ variables = pushVariable(variables, programVariable.name, event[dataElementId], allDes[dataElementId].dataElement.type, valueFound, '#' );
+ }
+ });
+ }
+ else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT"){
+ 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"){
+ //Only continue checking for a value if there is more than one event.
+ if(evs.all && evs.all.length > 1) {
+ var previousvalue = null;
+ var currentEventPassed = false;
+ for(var i = 0; i < evs.all.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 && evs.all[i] !== executingEvent &&
+ angular.isDefined(evs.all[i][dataElementId])) {
+ previousvalue = evs.all[i][dataElementId];
+ valueFound = true;
+ }
+ else if(evs.all[i] === executingEvent) {
+ //We have iterated to the newest event - store the last collected variable value - if any is found:
+ if(valueFound) {
+ variables = pushVariable(variables, 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;
+ variables = pushVariable(variables, 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( programStageId && evs.byStage[programStageId] ) {
+ numberOfEvents = evs.byStage[programStageId].length;
+ }
+ valueFound = true;
+ variables = pushVariable(variables, 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(dataElementId) {
+ var dataElement = allDes[dataElementId];
+ if( dataElement ) {
+ variables = pushVariable(variables, programVariable.name, "", dataElement.dataElement.type, false, '#' );
+ }
+ else {
+ $log.warn("Variable #{" + programVariable.name + "} is linked to a dataelement that is not part of the program");
+ variables = pushVariable(variables, programVariable.name, "", "string",false, '#' );
+ }
}
else {
- variableValue = false;
- }
- }
- else if(variableType === "int" || variableType === "number") {
- variableValue = Number(variableValue);
- }
- else{
- $log.warn("unknown datatype:" + variableType);
- }
-
- variables[variablename] = {
- variableValue:variableValue,
- variableType:variableType,
- hasValue:variablefound,
- variablePrefix:variablePrefix
- };
- };
- 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 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[dataElementId], allDes[dataElementId].dataElement.type, valueFound, '#' );
- }
- });
- }
- else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT"){
- if(angular.isDefined(currentEvent[dataElementId])
- && currentEvent[dataElementId] !== null ){
- valueFound = true;
- 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, 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 {
- pushVariable(programVariable.name, "", "string",false, '#' );
- }
- }
- });
-
- //add context variables:
- //last parameter "valuefound" is always true for event date
- pushVariable('incident_date', executingEvent.eventDate, 'date', true, 'V' );
- pushVariable('current_date', DateUtils.getToday(), 'date', true, 'V' );
- if(selectedEnrollment){
- pushVariable('enrollment_date', selectedEnrollment.dateOfEnrollment, '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;
+ variables = pushVariable(variables, programVariable.name, "", "string",false, '#' );
+ }
+ }
+ });
+
+ //add context variables:
+ //last parameter "valuefound" is always true for event date
+ variables = pushVariable(variables, 'incident_date', executingEvent.eventDate, 'date', true, 'V' );
+ variables = pushVariable(variables, 'current_date', DateUtils.getToday(), 'date', true, 'V' );
+ if(selectedEnrollment){
+ variables = pushVariable(variables, 'enrollment_date', selectedEnrollment.dateOfEnrollment, 'date', true, 'V' );
+ }
+
+ //variables = pushVariable(variables, 'value_count', executingEvent.eventDate, 'date', true, 'V' );
+ //variables = pushVariable(variables, 'zero_pos_value_count', executingEvent.eventDate, 'date', true, 'V' );
+
+ //Push all constant values:
+ angular.forEach(allProgramRules.constants, function(constant){
+ variables = pushVariable(variables, constant.id, constant.value, 'int', true, 'C' );
+ });
+
+ return variables;
}
};
})
/* service for executing tracker rules and broadcasting results */
-.service('TrackerRulesExecutionService', function(TrackerRulesFactory, MetaDataFactory, VariableService, $rootScope, $log, $q, $filter, orderByFilter){
+.service('TrackerRulesExecutionService', function(VariableService, $rootScope, $log, $filter, orderByFilter){
+
+ var replaceVariables = function(expression, variablesHash){
+ //replaces the variables in an expression with actual variable values.
+
+ //Check if the expression contains variables at all(any dollar signs):
+ if(expression.indexOf('#{') !== -1) {
+ //Find every variable name in the expression;
+ var variablespresent = expression.match(/#{\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("#{","").replace("}","");
+
+ 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);
+ }
+ else {
+ $log.warn("Expression " + expression + " conains variable " + variablepresent
+ + " - but this variable is not defined." );
+ }
+ });
+ }
+
+ //Check if the expression contains program variables
+ 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." );
+ }
+ });
+ }
+
+ //Check if the expression contains constants
+ 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;
+ };
+
+ 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.floor",parameters:1},
+ {name:"dhis.modulus",parameters:2},
+ {name:"dhis.hasValue",parameters:1},
+ {name:"dhis.concatenate"}];
+
+ angular.forEach(dhisFunctions, function(dhisFunction){
+ //Replace each * with a regex that matches each parameter, allowing commas only inside single quotation marks.
+ var regularExFunctionCall = new RegExp(dhisFunction.name.replace(".","\\.") + "\\([^\\)]*\\)",'g');
+ var callsToThisFunction = expression.match(regularExFunctionCall);
+ angular.forEach(callsToThisFunction, function(callToThisFunction){
+ //Remove the function name and paranthesis:
+ var justparameters = callToThisFunction.replace(/(^[^\(]+\()|\)$/g,"");
+ //Then split into single parameters:
+ var parameters = justparameters.match(/(('[^']+')|([^,]+))/g);
+
+ //Show error if no parameters is given and the function requires parameters,
+ //or if the number of parameters is wrong.
+ if(angular.isDefined(dhisFunction.parameters)){
+ //But we are only checking parameters where the dhisFunction actually has a defined set of parameters(concatenate, for example, does not have a fixed number);
+ if((!angular.isDefined(parameters) && dhisFunction.parameters > 0)
+ || parameters.length !== dhisFunction.parameters){
+ $log.warn(dhisFunction.name + " was called with the incorrect number of parameters");
+ }
+ }
+
+ //In case the function call is nested, the parameter itself contains an expression, run the expression.
+ if(angular.isDefined(parameters)) {
+ for (var i = 0; i < parameters.length; i++) {
+ parameters[i] = runExpression(parameters[i],dhisFunction.name,"parameter:" + i, flag, variablesHash);
+ }
+ }
+
+ //Special block for dhis.weeksBetween(*,*) - add such a block for all other dhis functions.
+ if(dhisFunction.name === "dhis.daysbetween")
+ {
+ var firstdate = $filter('trimquotes')(parameters[0]);
+ var seconddate = $filter('trimquotes')(parameters[1]);
+ firstdate = moment(firstdate);
+ seconddate = moment(seconddate);
+ //Replace the end evaluation of the dhis function:
+ expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'days'));
+ }
+ else if(dhisFunction.name === "dhis.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")
+ {
+ var dividend = Number(parameters[0]);
+ var divisor = Number(parameters[1]);
+ var rest = dividend % divisor;
+ //Replace the end evaluation of the dhis function:
+ expression = expression.replace(callToThisFunction, rest);
+ }
+ else if(dhisFunction.name === "dhis.hasValue")
+ {
+ //"evaluate" hasvalue to true or false:
+ if(variablesHash[parameters[0]].hasValue){
+ expression = expression.replace(callToThisFunction, 'true');
+ } else {
+ expression = expression.replace(callToThisFunction, 'false');
+ }
+ }
+ else if(dhisFunction.name === "dhis.concatenate")
+ {
+ var returnString = "'";
+ for (var i = 0; i < parameters.length; i++) {
+ returnString += parameters[i];
+ }
+ returnString += "'";
+ expression = expression.replace(callToThisFunction, returnString);
+ }
+ });
+ });
+ }
+
+ return expression;
+ };
+
+ var runExpression = function(expression, beforereplacement, identifier, flag, variablesHash ){
+ //determine if expression is true, and actions should be effectuated
+ //If DEBUG mode, use try catch and report errors. If not, omit the heavy try-catch loop.:
+ var answer = false;
+ if(flag.debug) {
+ try{
+
+ var dhisfunctionsevaluated = runDhisFunctions(expression, variablesHash, flag);
+ answer = eval(dhisfunctionsevaluated);
+
+ if(flag.verbose)
+ {
+ $log.info("Expression with id " + identifier + " was successfully run. Original condition was: " + beforereplacement + " - Evaluation ended up as:" + expression + " - Result of evaluation was:" + answer);
+ }
+ }
+ catch(e)
+ {
+ $log.warn("Expression with id " + identifier + " could not be run. Original condition was: " + beforereplacement + " - Evaluation ended up as:" + expression + " - error message:" + e);
+ }
+ }
+ else {
+ //Just run the expression. This is much faster than the debug route: http://jsperf.com/try-catch-block-loop-performance-comparison
+ var dhisfunctionsevaluated = runDhisFunctions(expression, variablesHash, flag);
+ answer = eval(dhisfunctionsevaluated);
+ }
+ return answer;
+ };
+
return {
- executeRules: function(programid, executingEvent, allEventsByStage, allDataElements, selectedEntity, selectedEnrollment, verbose ) {
- //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 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) {
- //Find every variable name in the expression;
- var variablespresent = expression.match(/#{\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("#{","").replace("}","");
-
- 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);
- }
- 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;
- };
-
- var runDhisFunctions = function(expression) {
- //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.floor",parameters:1},
- {name:"dhis.modulus",parameters:2},
- {name:"dhis.hasValue",parameters:1},
- {name:"dhis.concatenate"}];
-
- angular.forEach(dhisFunctions, function(dhisFunction){
- //Replace each * with a regex that matches each parameter, allowing commas only inside single quotation marks.
- var regularExFunctionCall = new RegExp(dhisFunction.name.replace(".","\\.") + "\\([^\\)]*\\)",'g');
- var callsToThisFunction = expression.match(regularExFunctionCall);
- angular.forEach(callsToThisFunction, function(callToThisFunction){
- //Remove the function name and paranthesis:
- var justparameters = callToThisFunction.replace(/(^[^\(]+\()|\)$/g,"");
- //Then split into single parameters:
- var parameters = justparameters.match(/(('[^']+')|([^,]+))/g);
-
- //Show error if no parameters is given and the function requires parameters,
- //or if the number of parameters is wrong.
- if(angular.isDefined(dhisFunction.parameters)){
- //But we are only checking parameters where the dhisFunction actually has a defined set of parameters(concatenate, for example, does not have a fixed number);
- if((!angular.isDefined(parameters) && dhisFunction.parameters > 0)
- || parameters.length !== dhisFunction.parameters){
- $log.warn(dhisFunction.name + " was called with the incorrect number of parameters");
- }
- }
-
- //In case the function call is nested, the parameter itself contains an expression, run the expression.
- if(angular.isDefined(parameters)) {
- for (var i = 0; i < parameters.length; i++) {
- parameters[i] = runExpression(parameters[i],dhisFunction.name,"parameter:" + i);
- }
- }
-
- //Special block for dhis.weeksBetween(*,*) - add such a block for all other dhis functions.
- if(dhisFunction.name === "dhis.daysbetween")
- {
- var firstdate = $filter('trimquotes')(parameters[0]);
- var seconddate = $filter('trimquotes')(parameters[1]);
- firstdate = moment(firstdate);
- seconddate = moment(seconddate);
- //Replace the end evaluation of the dhis function:
- expression = expression.replace(callToThisFunction, seconddate.diff(firstdate,'days'));
- }
- else if(dhisFunction.name === "dhis.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")
- {
- var dividend = Number(parameters[0]);
- var divisor = Number(parameters[1]);
- var rest = dividend % divisor;
- //Replace the end evaluation of the dhis function:
- expression = expression.replace(callToThisFunction, rest);
- }
- else if(dhisFunction.name === "dhis.hasValue")
- {
- //"evaluate" hasvalue to true or false:
- if(variablesHash[parameters[0]].hasValue){
- expression = expression.replace(callToThisFunction, 'true');
- } else {
- expression = expression.replace(callToThisFunction, 'false');
- }
- }
- else if(dhisFunction.name === "dhis.concatenate")
- {
- var returnString = "'";
- for (var i = 0; i < parameters.length; i++) {
- returnString += parameters[i];
- }
- returnString += "'";
- expression = expression.replace(callToThisFunction, returnString);
- }
- });
- });
- }
-
- return expression;
- };
-
- var runExpression = function(expression, beforereplacement, identifier ){
- //determine if expression is true, and actions should be effectuated
- //If DEBUG mode, use try catch and report errors. If not, omit the heavy try-catch loop.:
- var answer = false;
- if(debug) {
- try{
-
- var dhisfunctionsevaluated = runDhisFunctions(expression);
- answer = eval(dhisfunctionsevaluated);
-
- if(verbose)
- {
- $log.info("Expression with id " + identifier + " was successfully run. Original condition was: " + beforereplacement + " - Evaluation ended up as:" + expression + " - Result of evaluation was:" + answer);
- }
- }
- catch(e)
- {
- $log.warn("Expression with id " + identifier + " could not be run. Original condition was: " + beforereplacement + " - Evaluation ended up as:" + expression + " - error message:" + e);
- }
- }
- else {
- //Just run the expression. This is much faster than the debug route: http://jsperf.com/try-catch-block-loop-performance-comparison
- var dhisfunctionsevaluated = runDhisFunctions(expression);
- answer = eval(dhisfunctionsevaluated);
- }
- return answer;
- };
-
- 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;
- $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 });
- }
- }
-
- return true;
- });
- });
- });
+ executeRules: function(allProgramRules, executingEvent, evs, allDataElements, selectedEntity, selectedEnrollment, flag ) {
+ if(allProgramRules) {
+ var variablesHash = {};
+
+ //Concatenate rules produced by indicator definitions into the other rules:
+ var rules = $filter('filter')(allProgramRules.programRules, {programStageId: null});
+
+ if(executingEvent.programStage){
+ if(!rules) {
+ rules = [];
+ }
+ rules = rules.concat($filter('filter')(allProgramRules.programRules, {programStageId: executingEvent.programStage}));
+ }
+ if(!rules) {
+ rules = [];
+ }
+ rules = rules.concat(allProgramRules.programIndicators.rules);
+
+ //Run rules in priority - lowest number first(priority null is last)
+ rules = orderByFilter(rules, 'priority');
+
+ variablesHash = VariableService.getVariables(allProgramRules, executingEvent, evs, allDataElements, selectedEntity, selectedEnrollment);
+
+ 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, variablesHash);
+ }
+ //run expression:
+ ruleEffective = runExpression(expression, rule.condition, "rule:" + rule.id, flag, variablesHash);
+ } 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)
+ {
+ //Preserve old data for comparison:
+ var oldData = $rootScope.ruleeffects[executingEvent.event][action.id].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, variablesHash);
+ //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, flag, variablesHash);
+ }
+
+ if(oldData !== $rootScope.ruleeffects[executingEvent.event][action.id].data) {
+ updatedEffectsExits = true;
+ }
+ }
+
+ //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:
+ 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 });
+ }
+ }
+
+ return true;
+ }
}
};
});
\ No newline at end of file