=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java 2015-03-31 03:17:35 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/Program.java 2015-04-08 11:07:34 +0000 @@ -67,6 +67,8 @@ extends BaseIdentifiableObject implements VersionedObject { + private static final long serialVersionUID = -2807997671779497354L; + public static final List TYPE_LOOKUP = Arrays.asList( "", "MULTIPLE_EVENTS_WITH_REGISTRATION", "SINGLE_EVENT_WITH_REGISTRATION", "SINGLE_EVENT_WITHOUT_REGISTRATION" ); === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/programrule/ProgramRuleVariableSourceType.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/programrule/ProgramRuleVariableSourceType.java 2015-03-13 08:24:36 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/programrule/ProgramRuleVariableSourceType.java 2015-05-15 11:08:43 +0000 @@ -42,7 +42,8 @@ DATAELEMENT_PREVIOUS_EVENT("dataelement_previous_event"), CALCULATED_VALUE("calculated_value"), TEI_ATTRIBUTE("tei_attribute"), - CONTEXT_VARIABLE("context_variable"); + CONTEXT_VARIABLE("context_variable"), + NUMBEROFEVENTS_PROGRAMSTAGE("numberofevents_programstage"); private final String value; === 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-10 11:58:22 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry-controller.js 2015-06-10 13:45:11 +0000 @@ -3,8 +3,9 @@ trackerCapture.controller('DataEntryController', function($rootScope, $scope, - $modal, - $filter, + $modal, + $filter, + $log, $timeout, Paginator, DateUtils, @@ -17,8 +18,10 @@ OptionSetService, ModalService, CurrentSelection, - CustomFormService, - PeriodService) { + TrackerRulesExecutionService, + CustomFormService, + PeriodService) { + //Data entry form $scope.outerForm = {}; $scope.displayCustomForm = false; @@ -27,7 +30,11 @@ $scope.eventPeriods = []; $scope.currentPeriod = []; $scope.filterEvents = true; + $scope.showEventsAsTables = false; + //variable is set while looping through the program stages later. + $scope.stagesCanBeShownAsTable = false; $scope.showHelpText = {}; + $scope.hiddenFields = {}; var userProfile = SessionStorageService.get('USER_PROFILE'); var storedBy = userProfile && userProfile.username ? userProfile.username : ''; @@ -46,21 +53,56 @@ {color: 'alert-danger', description: 'overdue'}, {color: 'alert-default', description: 'skipped'} ]; - $scope.showEventColors = false; - + $scope.showEventColors = false; + + //listen for rule effect changes + $scope.$on('ruleeffectsupdated', function(event, args) { + angular.forEach($rootScope.ruleeffects, function(effect) { + if( effect.dataElement ) { + //in the data entry controller we only care about the "hidefield" actions + if(effect.action === "HIDEFIELD") { + if(effect.dataElement) { + //Hide the field if the hiding is in effect, and there is no data value in the field. + var hide = effect.ineffect && !$scope.currentEvent[effect.dataElement.id]; + $scope.hiddenFields[effect.dataElement.id] = hide; + } + else { + $log.warn("ProgramRuleAction " + effect.id + " is of type HIDEFIELD, bot does not have a dataelement defined"); + } + } + } + }); + }); + //check if field is hidden + $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; + } + else + { + return $scope.hiddenFields[id]; + } + }; + + //listen for the selected items $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.eventsByStage = []; - $scope.programStages = []; - $scope.prStDes = []; + $scope.programStages = []; + $rootScope.ruleeffects = {}; + $scope.prStDes = []; var selections = CurrentSelection.get(); $scope.selectedOrgUnit = SessionStorageService.get('SELECTED_OU'); @@ -84,6 +126,11 @@ $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) { + $scope.stagesCanBeShownAsTable = true; + } }); $scope.programStages = orderByFilter($scope.programStages, '-sortOrder').reverse(); @@ -147,8 +194,32 @@ $scope.schedulingEnabled = !$scope.schedulingEnabled; }; + $scope.stageCanBeShownAsTable = function(stage) { + if(stage.programStageDataElements && stage.programStageDataElements.length < 7) { + return true; + } + return false; + }; + + $scope.toggleEventsTableDisplay = function() { + $scope.showEventsAsTables = !$scope.showEventsAsTables; + angular.forEach($scope.programStages, function(stage){ + if(stage.programStageDataElements.length < 7) { + stage.displayEventsInTable = $scope.showEventsAsTables; + if($scope.currentStage === stage) { + $scope.getDataEntryForm(); + } + } + }); + }; + $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; } @@ -180,6 +251,10 @@ }, eventPeriods: function(){ return $scope.eventPeriods; + }, + autoCreate: function() { + //In case the programstage is a table, autocreate + return stage.displayEventsInTable; } } }); @@ -200,9 +275,14 @@ 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); } @@ -253,18 +333,31 @@ $scope.getDataEntryForm = function(){ $scope.currentStage = $scope.stagesById[$scope.currentEvent.programStage]; + $scope.currentStageEvents = $scope.eventsByStage[$scope.currentEvent.programStage]; angular.forEach($scope.currentStage.programStageSections, function(section){ section.open = true; }); $scope.customForm = CustomFormService.getForProgramStage($scope.currentStage, $scope.prStDes); - $scope.displayCustomForm = $scope.customForm ? true:false; + $scope.displayCustomForm = "default"; + if($scope.customForm){ + $scope.displayCustomForm = "custom"; + } + else if($scope.currentStage.displayEventsInTable) { + $scope.displayCustomForm = "table"; + } + + $scope.currentEventOriginal = angular.copy($scope.currentEvent); - $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; + + //Execute rules for the first time, to make the initial page appear correctly. + //Subsequent calls will be made from the "saveDataValue" function. + TrackerRulesExecutionService.executeRules($scope); }; function updateCurrentEventInStage(){ @@ -280,7 +373,14 @@ } }; - $scope.saveDatavalue = function(prStDe, field){ + + $scope.saveDatavalue = function(prStDe,field){ + $scope.saveDatavalueForEvent(prStDe,field,$scope.currentEvent); + }; + + $scope.saveDatavalueForEvent = function(prStDe,field,eventToSave,object){ + //Blank out the input-saved class on the last saved due date: + $scope.eventDateSaved = false; //console.log('the field: ', field); $scope.currentElement = {}; @@ -294,12 +394,17 @@ return false; } - //input is valid - var value = $scope.currentEvent[prStDe.dataElement.id]; - //var value = inputField.$viewValue; - - if($scope.currentEventOriginal[prStDe.dataElement.id] !== value){ - + //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(oldValue !== value){ if(value){ if(prStDe.dataElement.type === 'date'){ value = DateUtils.formatFromUserToApi(value); @@ -311,19 +416,21 @@ } } - $scope.currentElement = {id: prStDe.dataElement.id, saved: false}; - - 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, + $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: $scope.currentEvent.providedElsewhere[prStDe.dataElement.id] ? true : false + providedElsewhere: eventToSave.providedElsewhere[prStDe.dataElement.id] ? true : false } ] }; @@ -332,7 +439,12 @@ sortEventsByStage('UPDATE'); $scope.currentElement.saved = true; - $scope.currentEventOriginal = angular.copy($scope.currentEvent); + + $scope.currentEventOriginal = angular.copy($scope.currentEvent); + + $scope.currentStageEventsOriginal = angular.copy($scope.currentStageEvents); + + TrackerRulesExecutionService.executeRules($scope); }); } @@ -365,44 +477,46 @@ sortEventsByStage('UPDATE'); $scope.updateSuccess = true; - }); - } - }; - - $scope.saveEventDate = function(){ - + }); + } + }; + + $scope.saveEventDate = function () { + $scope.saveEventDateForEvent($scope.currentEvent); + }; + + $scope.saveEventDateForEvent = function(eventToSave){ $scope.eventDateSaved = false; - if($scope.currentEvent.eventDate === ''){ - $scope.invalidDate = true; + if(eventToSave.eventDate === ''){ + $scope.invalidDate = eventToSave.event; return false; } - var rawDate = angular.copy($scope.currentEvent.eventDate); - var convertedDate = DateUtils.format($scope.currentEvent.eventDate); + var rawDate = angular.copy(eventToSave.eventDate); + var convertedDate = DateUtils.format(eventToSave.eventDate); 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 === 'SCHEDULE' ? 'ACTIVE' : $scope.currentEvent.status, - program: $scope.currentEvent.program, - programStage: $scope.currentEvent.programStage, - orgUnit: $scope.currentEvent.dataValues && $scope.currentEvent.dataValues.length > 0 ? $scope.currentEvent.orgUnit : $scope.selectedOrgUnit.id, - eventDate: DateUtils.formatFromUserToApi($scope.currentEvent.eventDate), - trackedEntityInstance: $scope.currentEvent.trackedEntityInstance + 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 }; DHIS2EventFactory.updateForEventDate(e).then(function(data){ - $scope.currentEvent.sortingDate = $scope.currentEvent.eventDate; + eventToSave.sortingDate = eventToSave.eventDate; $scope.invalidDate = false; - $scope.eventDateSaved = true; - $scope.currentEvent.statusColor = EventUtils.getEventStatusColor($scope.currentEvent); - $scope.currentEvent.visited = true; - + $scope.eventDateSaved = eventToSave.event; + eventToSave.statusColor = EventUtils.getEventStatusColor(eventToSave); + sortEventsByStage(); updateCurrentEventInStage(); sortEventsByStage('UPDATE'); }); @@ -485,6 +599,8 @@ DHIS2EventFactory.update(dhis2Event).then(function(response){ $scope.currentEventOriginal = angular.copy($scope.currentEvent); + $scope.currentStageEventsOriginal = angular.copy($scope.currentStageEvents); + if(type === 'LAT' || type === 'LATLNG' ){ $scope.latitudeSaved = true; } @@ -529,15 +645,29 @@ $scope.note = ''; }; - $scope.getInputNotifcationClass = function(id, custom){ - if($scope.currentElement.id){ - if($scope.currentElement.saved && ($scope.currentElement.id === id)){ + $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)){ + if(!$scope.currentElement.saved && ($scope.currentElement.id === id && $scope.currentElement.event === event.event)){ if(custom){ return 'input-error'; } @@ -859,7 +989,8 @@ DialogService, stagesById, dummyEvent, - eventPeriods){ + eventPeriods, + autoCreate){ $scope.stagesById = stagesById; $scope.programStageId = dummyEvent.programStage; $scope.eventPeriods = eventPeriods; @@ -944,6 +1075,12 @@ } }); + + }; + + //If the caller wants to create right away, go ahead and save. + if(autoCreate) { + $scope.save(); }; $scope.cancel = function(){ === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html 2015-06-02 12:25:03 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/dataentry.html 2015-06-10 11:55:41 +0000 @@ -3,6 +3,8 @@ {{dataentryWidget.title| translate}} + + @@ -34,6 +36,7 @@ + @@ -76,7 +79,8 @@
-
+
+
{{currentEvent.reportDateDescription}}
-
-
-
+
+
+
+ +
+ === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html 2015-06-03 12:18:22 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/default-form.html 2015-06-10 11:55:41 +0000 @@ -14,7 +14,7 @@ - + {{prStDe.dataElement.formName ? prStDe.dataElement.formName : prStDe.dataElement.name}} @@ -158,7 +158,8 @@
- + + @@ -174,7 +175,7 @@ - +
{{prStDes[de.dataElement.id].dataElement.formName ? prStDes[de.dataElement.id].dataElement.formName : prStDes[de.dataElement.id].dataElement.name}} === added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/table-entry-form.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/table-entry-form.html 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dataentry/table-entry-form.html 2015-06-11 18:44:52 +0000 @@ -0,0 +1,153 @@ +
+ + + + + + + + + + + + +
+ {{currentEvent.reportDateDescription}} + + {{prStDe.dataElement.formName ? prStDe.dataElement.formName : prStDe.dataElement.name}} +
+ + {{'date_required'| translate}} + + +
+
+ + {{'number_required'| translate}} +
+
+
+
+ + {{'invalid'| translate}} +
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ {{'required'| translate}} +
+
+ +
+
=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js 2015-06-02 12:25:03 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js 2015-06-10 11:55:41 +0000 @@ -51,7 +51,7 @@ } $scope.selectedOrgUnit = SessionStorageService.get('SELECTED_OU'); - $scope.selectedEnrollment = {dateOfEnrollment: '', dateOfIncident: ''}; + $scope.selectedEnrollment = {dateOfEnrollment: $scope.today, dateOfIncident: $scope.today}; $scope.trackedEntities = {available: []}; TEService.getAll().then(function(entities){ === added directory 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound' === added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound/rulebound-controller.js' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound/rulebound-controller.js 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound/rulebound-controller.js 2015-06-02 05:55:14 +0000 @@ -0,0 +1,58 @@ +trackerCapture.controller('RuleBoundController', + function( + $rootScope, + $scope, + $log) { + + + $scope.widget = $scope.$parent.$parent.biggerWidget ? $scope.$parent.$parent.biggerWidget + : $scope.$parent.$parent.smallerWidget ? $scope.$parent.$parent.smallerWidget : null; + $scope.widgetTitle = $scope.widget.title; + $scope.widgetCode = $scope.widget.code; + + + $scope.displayTextEffects = {}; + $scope.displayKeyDataEffects = {}; + + //listen for updated rule effects + $scope.$on('ruleeffectsupdated', function(event, args) { + var textInEffect = false; + var keyDataInEffect = false; + + //Bind non-bound rule effects, if any. + angular.forEach($rootScope.ruleeffects, function(effect) { + if(effect.location == $scope.widgetCode){ + //This effect is affecting the local widget + + if(effect.action == "DISPLAYTEXT") { + //this action is display text. Make sure the displaytext is + //added to the local list of displayed texts + if(!angular.isObject($scope.displayTextEffects[effect.id])){ + $scope.displayTextEffects[effect.id] = effect; + } + if(effect.ineffect) + { + textInEffect = true; + } + } + else if(effect.action == "DISPLAYKEYVALUEPAIR") { + //this action is display text. Make sure the displaytext is + //added to the local list of displayed texts + if(!angular.isObject($scope.displayTextEffects[effect.id])){ + $scope.displayKeyDataEffects[effect.id] = effect; + } + if(effect.ineffect) + { + keyDataInEffect = true; + } + } else { + $log.warn("action: '" + effect.action + "' not supported by rulebound-controller.js") + } + } + }); + + $scope.showKeyDataSection = keyDataInEffect; + $scope.showTextSection = textInEffect; + + }); +}); \ No newline at end of file === added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound/rulebound.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound/rulebound.html 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/rulebound/rulebound.html 2015-06-02 05:55:14 +0000 @@ -0,0 +1,29 @@ +
+ +
+
+
+
{{item.content | trimquotes }}
+
{{item.data | trimquotes}}
+
+
+ + + + +
+
+ {{item.content | trimquotes}}{{item.data | trimquotes}} +
+
+
+
=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties 2015-06-02 12:25:03 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties 2015-06-10 11:55:41 +0000 @@ -106,6 +106,8 @@ new_event=New event create_new_event=Create new event create_new_event_repeatable=Create new event from a repeatable stage +toggle_table_view_on=Show events as tables where possible +toggle_table_view_off=Show data entry forms for each event event_recorded_on=Event recorded on at=at show_more=Click for more === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties 2015-01-20 11:51:34 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app_ar.properties 2015-06-08 08:54:37 +0000 @@ -1,261 +1,263 @@ -tracked_entity_management=\u0627\u062F\u0631\u0627\u0629 \u0627\u0644\u0643\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0645\u062A\u062A\u0628\u0639\u0629 -registering_unit=\u0648\u062D\u062F\u0629 \u062A\u0633\u062C\u064A\u0644 -program=\u0628\u0631\u0646\u0627\u0645\u062C -please_select=\u0631\u062C\u0627\u0621\u064B \u0627\u062E\u062A\u0631 -please_select_a_program=\u0631\u062C\u0627\u0621\u064B \u0627\u062E\u062A\u0631 \u0628\u0631\u0646\u0627\u0645\u062C\u0627\u064B -no_program_exists=\u0644\u0627\u064A\u0648\u062C\u062F \u0628\u0631\u0646\u0627\u0645\u062C -please_select_a_program_for_enrollment=\u0631\u062C\u0627\u0621\u064B \u0627\u062E\u062A\u0631 \u0628\u0631\u0646\u0627\u0645\u062C\u0627\u064B \u0644\u0644\u062A\u0633\u062C\u064A\u0644 -please_select_program_report=\u0631\u062C\u0627\u0621\u064B \u0627\u062E\u062A\u0631 \u0628\u0631\u0646\u0627\u0645\u062C\u0627\u064B \u0644\u0644\u0625\u0639\u062F\u0627\u062F -please_select_a_relationship=\u0631\u062C\u0627\u0621\u064B \u0627\u062E\u062A\u0631 \u0639\u0644\u0627\u0642\u0629 -no_relationship=\u0644\u0627\u062A\u0648\u062C\u062F \u0639\u0644\u0627\u0642\u0629 -relationship_not_possible=\u0644\u0627 \u064A\u0648\u062C\u062F \u0645\u062B\u0627\u0644 \u0644\u0643\u064A\u0627\u0646 \u0645\u062A\u0628\u0639 . \u0627\u0644\u0639\u0644\u0627\u0642\u0629 \u063A\u064A\u0631 \u0645\u0645\u0643\u0646\u0629 -no_program_exists_enrollment=\u0644\u0627\u064A\u0648\u062C\u062F \u0628\u0631\u0646\u0627\u0645\u062C \u0644\u0639\u0644\u0627\u0642\u0629 \u0627\u0644\u062A\u0646\u0638\u064A\u0645 \u0627\u0644\u0645\u062E\u062A\u0627\u0631\u0629 . \u0627\u0644\u062A\u0633\u062C\u064A\u0644 \u063A\u064A\u0631 \u0645\u0645\u0643\u0646 -no_program_exists_report=\u0644\u0627\u064A\u0648\u062C\u062F \u0628\u0631\u0646\u0627\u0645\u062C \u0644\u0639\u0644\u0627\u0642\u0629 \u0627\u0644\u062A\u0646\u0638\u064A\u0645 \u0627\u0644\u0645\u062E\u062A\u0627\u0631\u0629 . \u0627\u0644\u0627\u0639\u062F\u0627\u062F \u063A\u064A\u0631 \u0645\u0645\u0643\u0646 -not_yet_enrolled_data_entry=\u063A\u064A\u0631 \u0645\u0633\u062C\u0644 \u062D\u062A\u0649 \u0627\u0644\u0644\u0622\u0646 . \u0627\u062F\u062E\u0627\u0644 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u063A\u064A\u0631 \u0645\u0645\u0643\u0646 -not_yet_enrolled_enrollment=\u063A\u064A\u0631 \u0645\u0633\u062C\u0644 \u062D\u062A\u0649 \u0627\u0644\u0644\u0622\u0646 . \u0631\u062C\u0627\u0621\u064B \u0633\u062C\u0644 -not_active_enrollment_exists=\u0644\u0627\u064A\u0648\u062C\u062F \u062A\u0633\u062C\u064A\u0644 \u0641\u0639\u0627\u0644 \u0644\u0644\u0628\u0631\u0646\u0627\u0645\u062C \u0627\u0644\u0645\u062E\u062A\u0627\u0631 -not_yet_enrolled_note=\u063A\u064A\u0631 \u0645\u0633\u062C\u0644 \u062D\u062A\u0649 \u0627\u0644\u0622\u0646 . \u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u063A\u064A\u0631 \u0645\u0645\u0643\u0646 -not_yet_enrolled_report=\u063A\u064A\u0631 \u0645\u0633\u062C\u0644 \u062D\u062A\u0649 \u0627\u0644\u0622\u0646 . \u0627\u0644\u0627\u0639\u062F\u0627\u062F \u063A\u064A\u0631 \u0645\u0645\u0643\u0646 -no_data_report=\u0644\u0627\u064A\u0648\u062C\u062F \u062A\u0633\u062C\u064A\u0644 \u0644\u064A\u062A\u0645 \u0627\u0644\u0627\u0639\u062F\u0627\u062F -empty_notes=\u0644\u0627\u0626\u062D\u0629 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0627\u062A \u0627\u0644\u0641\u0627\u0631\u063A\u0629 -no_event_is_yet_created=\u0644\u0627\u064A\u0648\u062C\u062F \u062D\u062F\u062B \u0645\u062A\u0648\u0641\u0631 \u0644\u0627\u062F\u062E\u0627\u0644 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A . \u0631\u062C\u0627\u0621\u064B \u0627\u0646\u0634\u0626 \u0648\u0627\u062D\u062F\u0627\u064B -event_creation=\u0631\u062C\u0627\u0621\u064B \u0627\u0646\u0634\u0626 \u0648\u0627\u062D\u062F\u0627\u064B \u0645\u0646 \u0627\u0644\u0623\u0633\u0641\u0644 -not_selected=\u063A\u064A\u0631 \u0645\u062E\u062A\u0627\u0631 +tracked_entity_management=\u0627\u062f\u0631\u0627\u0629 \u0627\u0644\u0643\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u062a\u062a\u0628\u0639\u0629 +registering_unit=\u0648\u062d\u062f\u0629 \u062a\u0633\u062c\u064a\u0644 +program=\u0628\u0631\u0646\u0627\u0645\u062c +please_select=\u0631\u062c\u0627\u0621\u064b \u0627\u062e\u062a\u0631 +please_select_a_program=\u0631\u062c\u0627\u0621\u064b \u0627\u062e\u062a\u0631 \u0628\u0631\u0646\u0627\u0645\u062c\u0627\u064b +no_program_exists=\u0644\u0627\u064a\u0648\u062c\u062f \u0628\u0631\u0646\u0627\u0645\u062c +please_select_a_program_for_enrollment=\u0631\u062c\u0627\u0621\u064b \u0627\u062e\u062a\u0631 \u0628\u0631\u0646\u0627\u0645\u062c\u0627\u064b \u0644\u0644\u062a\u0633\u062c\u064a\u0644 +please_select_program_report=\u0631\u062c\u0627\u0621\u064b \u0627\u062e\u062a\u0631 \u0628\u0631\u0646\u0627\u0645\u062c\u0627\u064b \u0644\u0644\u0625\u0639\u062f\u0627\u062f +please_select_a_relationship=\u0631\u062c\u0627\u0621\u064b \u0627\u062e\u062a\u0631 \u0639\u0644\u0627\u0642\u0629 +no_relationship=\u0644\u0627\u062a\u0648\u062c\u062f \u0639\u0644\u0627\u0642\u0629 +relationship_not_possible=\u0644\u0627 \u064a\u0648\u062c\u062f \u0645\u062b\u0627\u0644 \u0644\u0643\u064a\u0627\u0646 \u0645\u062a\u0628\u0639 . \u0627\u0644\u0639\u0644\u0627\u0642\u0629 \u063a\u064a\u0631 \u0645\u0645\u0643\u0646\u0629 +no_program_exists_enrollment=\u0644\u0627\u064a\u0648\u062c\u062f \u0628\u0631\u0646\u0627\u0645\u062c \u0644\u0639\u0644\u0627\u0642\u0629 \u0627\u0644\u062a\u0646\u0638\u064a\u0645 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629 . \u0627\u0644\u062a\u0633\u062c\u064a\u0644 \u063a\u064a\u0631 \u0645\u0645\u0643\u0646 +no_program_exists_report=\u0644\u0627\u064a\u0648\u062c\u062f \u0628\u0631\u0646\u0627\u0645\u062c \u0644\u0639\u0644\u0627\u0642\u0629 \u0627\u0644\u062a\u0646\u0638\u064a\u0645 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629 . \u0627\u0644\u0627\u0639\u062f\u0627\u062f \u063a\u064a\u0631 \u0645\u0645\u0643\u0646 +not_yet_enrolled_data_entry=\u063a\u064a\u0631 \u0645\u0633\u062c\u0644 \u062d\u062a\u0649 \u0627\u0644\u0644\u0622\u0646 . \u0627\u062f\u062e\u0627\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u063a\u064a\u0631 \u0645\u0645\u0643\u0646 +not_yet_enrolled_enrollment=\u063a\u064a\u0631 \u0645\u0633\u062c\u0644 \u062d\u062a\u0649 \u0627\u0644\u0644\u0622\u0646 . \u0631\u062c\u0627\u0621\u064b \u0633\u062c\u0644 +not_active_enrollment_exists=\u0644\u0627\u064a\u0648\u062c\u062f \u062a\u0633\u062c\u064a\u0644 \u0641\u0639\u0627\u0644 \u0644\u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0627\u0644\u0645\u062e\u062a\u0627\u0631 +not_yet_enrolled_note=\u063a\u064a\u0631 \u0645\u0633\u062c\u0644 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646 . \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u0645\u0644\u0627\u062d\u0638\u0629 \u063a\u064a\u0631 \u0645\u0645\u0643\u0646 +not_yet_enrolled_report=\u063a\u064a\u0631 \u0645\u0633\u062c\u0644 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646 . \u0627\u0644\u0627\u0639\u062f\u0627\u062f \u063a\u064a\u0631 \u0645\u0645\u0643\u0646 +no_data_report=\u0644\u0627\u064a\u0648\u062c\u062f \u062a\u0633\u062c\u064a\u0644 \u0644\u064a\u062a\u0645 \u0627\u0644\u0627\u0639\u062f\u0627\u062f +empty_notes=\u0644\u0627\u0626\u062d\u0629 \u0627\u0644\u0645\u0644\u0627\u062d\u0638\u0627\u062a \u0627\u0644\u0641\u0627\u0631\u063a\u0629 +no_event_is_yet_created=\u0644\u0627\u064a\u0648\u062c\u062f \u062d\u062f\u062b \u0645\u062a\u0648\u0641\u0631 \u0644\u0627\u062f\u062e\u0627\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a . \u0631\u062c\u0627\u0621\u064b \u0627\u0646\u0634\u0626 \u0648\u0627\u062d\u062f\u0627\u064b +event_creation=\u0631\u062c\u0627\u0621\u064b \u0627\u0646\u0634\u0626 \u0648\u0627\u062d\u062f\u0627\u064b \u0645\u0646 \u0627\u0644\u0623\u0633\u0641\u0644 +not_selected=\u063a\u064a\u0631 \u0645\u062e\u062a\u0627\u0631 create=\u0627\u0646\u0634\u0626 view_all=\u0627\u0639\u0631\u0636 \u0627\u0644\u0643\u0644 -list_all_entities=\u0627\u062F\u0631\u062C \u0643\u0644 \u0627\u0644\u0643\u064A\u0627\u0646\u0627\u062A -list_all=\u0627\u062F\u0631\u062C \u0627\u0644\u0643\u0644 -list=\u0627\u062F\u0631\u062C -invalid=\u063A\u064A\u0631 \u0635\u0627\u0644\u062D +list_all_entities=\u0627\u062f\u0631\u062c \u0643\u0644 \u0627\u0644\u0643\u064a\u0627\u0646\u0627\u062a +list_all=\u0627\u062f\u0631\u062c \u0627\u0644\u0643\u0644 +list=\u0627\u062f\u0631\u062c +invalid=\u063a\u064a\u0631 \u0635\u0627\u0644\u062d required=\u0645\u0637\u0644\u0648\u0628 number_required=\u0631\u0642\u0645 \u0645\u0637\u0644\u0648\u0628 -date_required=\u0628\u064A\u0627\u0646\u0627\u062A \u0645\u0637\u0644\u0648\u0628\u0629 -filter=\u062A\u0635\u0641\u064A\u0629 -search=\u0628\u062D\u062B -_search=\u0627\u0628\u062D\u062B -advanced_search=\u0628\u062D\u062B \u0645\u062A\u0642\u062F\u0645 -search_for=\u0627\u0628\u062D\u062B \u0639\u0646 -type_your_search_criteria_here=\u062F\u0648\u0650\u0646 \u0645\u0639\u0627\u064A\u064A\u0631 \u0627\u0644\u0628\u062D\u062B \u0647\u0646\u0627 -search_input_required=\u0631\u062C\u0627\u0621\u064B \u062D\u062F\u062F \u0645\u0639\u0627\u064A\u064A\u0631 \u0627\u0644\u0628\u062D\u062B -in_progress=\u0642\u064A\u062F \u0627\u0644\u0639\u0645\u0644 -registered_entities=\u0643\u064A\u0627\u0646\u0627\u062A \u0645\u0633\u062C\u0644\u0629 -empty_entity_list=\u0644\u0627\u062A\u0648\u062C\u062F \u0643\u064A\u0627\u0646\u0627\u062A \u0645\u0633\u062C\u0644\u0629 -empty=\u0641\u0627\u0631\u063A -form_is_empty_fill_at_least_one=\u0627\u0644\u0627\u0633\u062A\u0645\u0627\u0631\u0629 \u0641\u0627\u0631\u063A\u0629 . \u0631\u062C\u0627\u0621\u064B \u0627\u0645\u0644\u0623 \u0648\u0627\u062D\u062F\u0629 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 -total_number_of_pages=\u0639\u062F\u062F \u0627\u0644\u0635\u0641\u062D\u0627\u062A -rows_per_page=\u0639\u062F\u062F \u0627\u0644\u0635\u0641\u0648\u0641 \u0641\u064A \u0643\u0644 \u0635\u0641\u062D\u0629 -jump_to_page=\u0627\u0646\u062A\u0642\u0644 \u0627\u0644\u0649 \u0635\u0641\u062D\u0629 -page=\u0635\u0641\u062D\u0629 -first=\u0623\u0648\u0644\u0627\u064B +date_required=\u0628\u064a\u0627\u0646\u0627\u062a \u0645\u0637\u0644\u0648\u0628\u0629 +filter=\u062a\u0635\u0641\u064a\u0629 +search=\u0628\u062d\u062b +_search=\u0627\u0628\u062d\u062b +advanced_search=\u0628\u062d\u062b \u0645\u062a\u0642\u062f\u0645 +search_for=\u0627\u0628\u062d\u062b \u0639\u0646 +type_your_search_criteria_here=\u062f\u0648\u0650\u0646 \u0645\u0639\u0627\u064a\u064a\u0631 \u0627\u0644\u0628\u062d\u062b \u0647\u0646\u0627 +search_input_required=\u0631\u062c\u0627\u0621\u064b \u062d\u062f\u062f \u0645\u0639\u0627\u064a\u064a\u0631 \u0627\u0644\u0628\u062d\u062b +in_progress=\u0642\u064a\u062f \u0627\u0644\u0639\u0645\u0644 +registered_entities=\u0643\u064a\u0627\u0646\u0627\u062a \u0645\u0633\u062c\u0644\u0629 +empty_entity_list=\u0644\u0627\u062a\u0648\u062c\u062f \u0643\u064a\u0627\u0646\u0627\u062a \u0645\u0633\u062c\u0644\u0629 +empty=\u0641\u0627\u0631\u063a +form_is_empty_fill_at_least_one=\u0627\u0644\u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0641\u0627\u0631\u063a\u0629 . \u0631\u062c\u0627\u0621\u064b \u0627\u0645\u0644\u0623 \u0648\u0627\u062d\u062f\u0629 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 +total_number_of_pages=\u0639\u062f\u062f \u0627\u0644\u0635\u0641\u062d\u0627\u062a +rows_per_page=\u0639\u062f\u062f \u0627\u0644\u0635\u0641\u0648\u0641 \u0641\u064a \u0643\u0644 \u0635\u0641\u062d\u0629 +jump_to_page=\u0627\u0646\u062a\u0642\u0644 \u0627\u0644\u0649 \u0635\u0641\u062d\u0629 +page=\u0635\u0641\u062d\u0629 +first=\u0623\u0648\u0644\u0627\u064b previous=\u0627\u0644\u0633\u0627\u0628\u0642 -next=\u0627\u0644\u062A\u0627\u0644\u064A -last=\u0627\u062E\u064A\u0631 -go_to_dashboard=\u0627\u0630\u0647\u0628 \u0627\u0644\u0649 \u0644\u0648\u062D\u0629 \u0627\u0644\u0639\u062F\u0627\u062F\u0627\u062A +next=\u0627\u0644\u062a\u0627\u0644\u064a +last=\u0627\u062e\u064a\u0631 +go_to_dashboard=\u0627\u0630\u0647\u0628 \u0627\u0644\u0649 \u0644\u0648\u062d\u0629 \u0627\u0644\u0639\u062f\u0627\u062f\u0627\u062a go=\u0627\u0630\u0647\u0628 -edit=\u062A\u062D\u0631\u064A\u0631 -edit_profile=\u062D\u0631\u0631 \u0627\u0644\u062A\u0634\u0643\u064A\u0644 \u0627\u0644\u062C\u0627\u0646\u0628\u064A -association=\u0646\u0638\u0650\u0645 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0627\u062A +edit=\u062a\u062d\u0631\u064a\u0631 +edit_profile=\u062d\u0631\u0631 \u0627\u0644\u062a\u0634\u0643\u064a\u0644 \u0627\u0644\u062c\u0627\u0646\u0628\u064a +association=\u0646\u0638\u0650\u0645 \u0627\u0644\u0645\u0634\u0627\u0631\u0643\u0627\u062a change_location=\u0646\u0638\u0650\u0645 \u0627\u0644\u0645\u0648\u0642\u0639 -details_history=\u062A\u0641\u0627\u0635\u064A\u0644/\u062A\u0627\u0631\u064A\u062E -history=\u062A\u0627\u0631\u064A\u062E +details_history=\u062a\u0641\u0627\u0635\u064a\u0644/\u062a\u0627\u0631\u064a\u062e +history=\u062a\u0627\u0631\u064a\u062e complete=\u0627\u0643\u0645\u0644 terminate=\u0627\u0646\u0647\u0627\u0621 -completed=\u0645\u0643\u062A\u0645\u0644 -terminated=\u0645\u0646\u062A\u0647\u064A -delete=\u0627\u062D\u0630\u0641 +completed=\u0645\u0643\u062a\u0645\u0644 +terminated=\u0645\u0646\u062a\u0647\u064a +delete=\u0627\u062d\u0630\u0641 remove=\u0627\u0632\u0644 -entity=\u0643\u064A\u0627\u0646 -clear=\u0627\u0645\u0633\u062D +entity=\u0643\u064a\u0627\u0646 +clear=\u0627\u0645\u0633\u062d add=\u0623\u0636\u0641 -add_note=\u0623\u0636\u0641 \u0645\u0644\u0627\u062D\u0638\u0629 -search_note=\u0627\u0628\u062D\u062B \u0639\u0646 \u0645\u0644\u0627\u062D\u0638\u0627\u062A -add_new_note_here=\u0627\u0636\u0641 \u0645\u0644\u0627\u062D\u0638\u0629 \u062C\u062F\u064A\u062F\u0629 \u0647\u0646\u0627 -skipped=\u0645\u062A\u062E\u0637\u0649 -skip=\u062A\u062E\u0637\u0649 -unskip=\u062C\u062F\u0648\u0644\u0629 \u0633\u0627\u0628\u0642\u0629 -complete=\u0645\u0643\u062A\u0645\u0644 -incomplete=\u063A\u064A\u0631 \u0645\u0643\u062A\u0645\u0644 -validate=\u062A\u062D\u0642\u0642 \u0645\u0646 \u0627\u0644\u0635\u062D\u0629 -status=\u062D\u0627\u0644\u0629 -details=\u062A\u0641\u0627\u0635\u064A\u0644 -_details=\u062A\u0641\u0627\u0635\u064A\u0644 -created_by=\u0645\u0633\u062C\u0644 \u0628\u0648\u0627\u0633\u0637\u0629 -date=\u062A\u0627\u0631\u064A\u062E -_date=\u062A\u0627\u0631\u064A\u062E -add_new=\u0623\u0635\u0641 \u062C\u062F\u064A\u062F\u0627\u064B -event_name=\u0627\u0633\u0645 \u0627\u0644\u062D\u062F\u062B -new_event=\u062D\u062F\u062B \u062C\u062F\u064A\u062F -create_new_event=\u0627\u0646\u0634\u0626 \u062D\u062F\u062B\u0627\u064B \u062C\u062F\u064A\u062F\u0627\u064B -create_new_event_repeatable=\u0627\u0646\u0634\u0626 \u062D\u062F\u062B\u0627\u064B \u062C\u062F\u064A\u062F\u0627\u064B \u0645\u0646 \u0645\u0631\u062D\u0644\u0629 \u0645\u0645\u0643\u0646 \u0627\u0639\u0627\u062F\u062A\u0647\u0627 -close_search=\u0627\u063A\u0644\u0642 \u0627\u0644\u0628\u062D\u062B -search_attributes=\u062E\u0635\u0627\u0626\u0635 \u0627\u0644\u0628\u062D\u062B -available_search_attributes=\u062E\u0635\u0627\u0626\u0635 \u0627\u0644\u0628\u062D\u062B \u0627\u0644\u0645\u062A\u0648\u0641\u0631\u0629 -selected_search_attributes=\u062E\u0635\u0627\u0626\u0635 \u0627\u0644\u0628\u062D\u062B \u0627\u0644\u0645\u062E\u062A\u0627\u0631\u0629 -search_for_dashboard=\u0627\u0628\u062D\u062B \u0639\u0646 \u0639\u0646\u0627\u0635\u0631 \u0644\u0648\u062D\u0629 \u0627\u0644\u0639\u062F\u0627\u062F\u0627\u062A -dashboard=\u0644\u0648\u062D\u0629 \u0627\u0644\u0639\u062F\u0627\u062F\u0627\u062A -home=\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0631\u0626\u0633\u064A\u0629 -back=\u0644\u0644\u062E\u0644\u0641 -profile=\u062A\u0634\u0643\u064A\u0644 \u062C\u0627\u0646\u0628\u064A -enrollment=\u062A\u0633\u062C\u064A\u0644 -delete_enrollment=\u0627\u0644\u063A\u0650 \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -terminate_enrollment=\u0627\u0646\u0647\u0650 \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -complete_enrollment=\u0627\u0643\u0645\u0644 \u0627\u0644\u062A\u0633\u062C\u0628\u0644 -enrollment_date=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -notes=\u0645\u0644\u0627\u062D\u0638\u0627\u062A +add_note=\u0623\u0636\u0641 \u0645\u0644\u0627\u062d\u0638\u0629 +search_note=\u0627\u0628\u062d\u062b \u0639\u0646 \u0645\u0644\u0627\u062d\u0638\u0627\u062a +add_new_note_here=\u0627\u0636\u0641 \u0645\u0644\u0627\u062d\u0638\u0629 \u062c\u062f\u064a\u062f\u0629 \u0647\u0646\u0627 +skipped=\u0645\u062a\u062e\u0637\u0649 +skip=\u062a\u062e\u0637\u0649 +unskip=\u062c\u062f\u0648\u0644\u0629 \u0633\u0627\u0628\u0642\u0629 +complete=\u0645\u0643\u062a\u0645\u0644 +incomplete=\u063a\u064a\u0631 \u0645\u0643\u062a\u0645\u0644 +validate=\u062a\u062d\u0642\u0642 \u0645\u0646 \u0627\u0644\u0635\u062d\u0629 +status=\u062d\u0627\u0644\u0629 +details=\u062a\u0641\u0627\u0635\u064a\u0644 +_details=\u062a\u0641\u0627\u0635\u064a\u0644 +created_by=\u0645\u0633\u062c\u0644 \u0628\u0648\u0627\u0633\u0637\u0629 +date=\u062a\u0627\u0631\u064a\u062e +_date=\u062a\u0627\u0631\u064a\u062e +add_new=\u0623\u0635\u0641 \u062c\u062f\u064a\u062f\u0627\u064b +event_name=\u0627\u0633\u0645 \u0627\u0644\u062d\u062f\u062b +new_event=\u062d\u062f\u062b \u062c\u062f\u064a\u062f +create_new_event=\u0627\u0646\u0634\u0626 \u062d\u062f\u062b\u0627\u064b \u062c\u062f\u064a\u062f\u0627\u064b +create_new_event_repeatable=\u0627\u0646\u0634\u0626 \u062d\u062f\u062b\u0627\u064b \u062c\u062f\u064a\u062f\u0627\u064b \u0645\u0646 \u0645\u0631\u062d\u0644\u0629 \u0645\u0645\u0643\u0646 \u0627\u0639\u0627\u062f\u062a\u0647\u0627 +toggle_table_view_on=\u0645\u0634\u0627\u0647\u062f\u0629 \u0623\u062d\u062f\u0627\u062b \u0643\u062c\u062f\u0627\u0648\u0644 \u062d\u064a\u062b\u0645\u0627 \u0623\u0645\u0643\u0646(\u062c\u0648\u062c\u0644 \u062a\u0631\u062c\u0645\u0629) +toggle_table_view_off=\u0646\u0645\u0627\u0630\u062c \u0625\u062f\u062e\u0627\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u062a\u0638\u0647\u0631 \u0644\u0643\u0644 \u062d\u062f\u062b(\u062c\u0648\u062c\u0644 \u062a\u0631\u062c\u0645\u0629) +close_search=\u0627\u063a\u0644\u0642 \u0627\u0644\u0628\u062d\u062b +search_attributes=\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0628\u062d\u062b +available_search_attributes=\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0628\u062d\u062b \u0627\u0644\u0645\u062a\u0648\u0641\u0631\u0629 +selected_search_attributes=\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u0628\u062d\u062b \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629 +search_for_dashboard=\u0627\u0628\u062d\u062b \u0639\u0646 \u0639\u0646\u0627\u0635\u0631 \u0644\u0648\u062d\u0629 \u0627\u0644\u0639\u062f\u0627\u062f\u0627\u062a +dashboard=\u0644\u0648\u062d\u0629 \u0627\u0644\u0639\u062f\u0627\u062f\u0627\u062a +home=\u0627\u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0631\u0626\u0633\u064a\u0629 +back=\u0644\u0644\u062e\u0644\u0641 +profile=\u062a\u0634\u0643\u064a\u0644 \u062c\u0627\u0646\u0628\u064a +enrollment=\u062a\u0633\u062c\u064a\u0644 +delete_enrollment=\u0627\u0644\u063a\u0650 \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +terminate_enrollment=\u0627\u0646\u0647\u0650 \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +complete_enrollment=\u0627\u0643\u0645\u0644 \u0627\u0644\u062a\u0633\u062c\u0628\u0644 +enrollment_date=\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +notes=\u0645\u0644\u0627\u062d\u0638\u0627\u062a relationship=\u0639\u0644\u0627\u0642\u0629 -relationships=\u0639\u0644\u0627\u0642\u0627\u062A +relationships=\u0639\u0644\u0627\u0642\u0627\u062a add_relationship=\u0627\u0636\u0641 \u0639\u0644\u0627\u0642\u0629 a_is_to_b=\u0639\u0644\u0627\u0642\u0629 (\u0623) \u0644\u0640\u0640 (\u0628) b_is_to_a=\u0639\u0644\u0627\u0642\u0629 (\u0628) \u0644\u0640\u0640 (\u0623) -please_select_source=\u0631\u062C\u0627\u0621\u064B \u0627\u062E\u062A\u0631 \u0645\u0635\u062F\u0631\u0627\u064B -register_new=\u0633\u062C\u0644 \u062C\u062F\u064A\u062F\u0627\u064B -search_from_existing=\u0627\u0628\u062D\u062B \u0628\u0645\u0639\u064A\u0627\u0631 \u0645\u062A\u0649 \u062A\u0645 \u0627\u0644\u0627\u0646\u0634\u0627\u0621 +please_select_source=\u0631\u062c\u0627\u0621\u064b \u0627\u062e\u062a\u0631 \u0645\u0635\u062f\u0631\u0627\u064b +register_new=\u0633\u062c\u0644 \u062c\u062f\u064a\u062f\u0627\u064b +search_from_existing=\u0627\u0628\u062d\u062b \u0628\u0645\u0639\u064a\u0627\u0631 \u0645\u062a\u0649 \u062a\u0645 \u0627\u0644\u0627\u0646\u0634\u0627\u0621 name=\u0627\u0633\u0645 -dataentry=\u0627\u062F\u062E\u0627\u0644 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A -custom_form=\u0627\u0633\u062A\u0645\u0627\u0631\u0629 \u0645\u062E\u0635\u0635\u0629 -default_form=\u0627\u0633\u062A\u0645\u0627\u0631\u0629 \u0627\u0641\u062A\u0631\u0627\u0636\u064A\u0629 +dataentry=\u0627\u062f\u062e\u0627\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a +custom_form=\u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0645\u062e\u0635\u0635\u0629 +default_form=\u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629 menu=\u0642\u0627\u0626\u0645\u0629 -tracker_reports=\u062A\u0642\u0627\u0631\u064A\u0631 \u0645\u064F\u062A\u064E\u062A\u064E\u0628\u0650\u0639\u064E\u0629 -reports=\u062A\u0642\u0627\u0631\u064A\u0631 -registration_and_data_entry=\u0627\u0644\u062A\u0633\u062C\u064A\u0644 \u0648 \u0627\u062F\u062E\u0627\u0644 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A -program_summary_report=\u062A\u0642\u0631\u064A\u0631 \u0645\u0644\u062E\u0635 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C -program_summary=\u0645\u0644\u062E\u0635 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C -program_summary_description=\u0627\u0635\u062F\u0631 \u062A\u0642\u0631\u064A\u0631\u0627\u064B \u0645\u0644\u062E\u0635\u0627\u064B \u0644\u0648\u062D\u062F\u0629 \u062A\u0646\u0638\u064A\u0645 \u0628\u0631\u0646\u0627\u0645\u062C \u0645\u062E\u0635\u0635\u0629 \u0648 \u0627\u0637\u0627\u0631\u0627\u064B \u0632\u0645\u0646\u064A\u0627\u064B . \u064A\u0642\u062F\u0645 \u0627\u0644\u062A\u0642\u0631\u064A\u0631 \u0644\u0627\u0626\u062D\u0629\u064B \u0628\u0623\u0645\u062B\u0644\u0629 \u0627\u0644\u0643\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0645\u062A\u0628\u0639\u0629 \u0628\u0627\u0644\u0627\u0636\u0627\u0641\u0629 \u0627\u0644\u0649 \u062E\u064A\u0627\u0631 \u0627\u0644\u062A\u0639\u0645\u0642 \u0648 \u0631\u0624\u064A\u0629 \u0627\u0644\u0642\u064A\u0645 \u0627\u0644\u0641\u0639\u0644\u064A\u0629 -program_statistics_report=\u062A\u0642\u0631\u064A\u0631 \u0627\u062D\u0635\u0627\u0626\u064A\u0627\u062A \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C -program_statistics=\u0627\u062D\u0635\u0627\u0626\u064A\u0627\u062A \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C -program_statistics_description= \u0627\u0635\u062F\u0631 \u062A\u0642\u0631\u064A\u0631\u0627\u064B\u0627\u062D\u0635\u0627\u0626\u064A\u0627\u064B \u0644\u0628\u0631\u0646\u0627\u0645\u062C \u0645\u0639\u064A\u0646 . \u064A\u062D\u0648\u064A \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C \u0639\u0644\u0649 \u0633\u0628\u064A\u0644 \u0627\u0644\u0645\u062B\u0627\u0644 \u0648\u0635\u0641\u0627\u064B \u0639\u0627\u0645\u0627\u064B \u0639\u0646 \u0627\u0644\u0627\u0646\u0642\u0637\u0627\u0639\u0627\u062A \u0627\u0648 \u0646\u0633\u0628 \u0627\u0644\u0627\u0643\u0645\u0627\u0644 \u0641\u064A \u0627\u0637\u0627\u0631 \u0632\u0645\u0646\u064A \u0645\u0623\u062E\u0648\u0630 \u0628\u0639\u064A\u0646 \u0627\u0644\u0627\u0639\u062A\u0628\u0627\u0631 \u0641\u064A \u0648\u062D\u062F\u0629 \u062A\u0646\u0638\u064A\u0645 \u0645\u062E\u0635\u0635\u0629 -upcoming_events=\u0627\u062D\u062F\u0627\u062B \u062A\u0627\u0644\u064A\u0629 -upcoming_events_description=\u0627\u0635\u062F\u0631 \u062A\u0642\u0631\u064A\u0631\u0627\u064B \u062C\u062F\u0648\u0644\u064A\u0627\u064B \u064A\u0638\u0647\u0631 \u0641\u064A\u0647 \u0623\u0645\u062B\u0644\u0629 \u0639\u0646 \u0643\u064A\u0627\u0646\u0627\u062A \u0645\u062A\u0628\u0639\u0629 \u0648 \u0623\u062D\u062F\u0627\u062B\u0647\u0645 \u0627\u0644\u0645\u0631\u062A\u0642\u0628\u0629 \u0644\u0628\u0631\u0646\u0627\u0645\u062C \u0648 \u0648\u0642\u062A \u0645\u062D\u062F\u062F\u064A\u0646 . \u062A\u0635\u0646\u064A\u0641 \u0627\u0644\u0628\u062D\u062B \u0648 \u0627\u0638\u0647\u0627\u0631\\u0627\u062E\u0641\u0627\u0621 \u0627\u0644\u0639\u0645\u0644\u064A\u0627\u062A \u0645\u0645\u0643\u0646\u0627\u062A \u0641\u064A \u0627\u0644\u0623\u0639\u0645\u062F\u0629 -overdue_events=\u0627\u062D\u062F\u0627\u062B \u063A\u064A\u0631 \u0645\u0646\u062C\u0632\u0629 -overdue_events_description=\u0627\u0635\u062F\u0631 \u0644\u0627\u0626\u062D\u0629 \u0645\u0646 \u0623\u062D\u062F\u0627\u062B \u0644\u0628\u0631\u0646\u0627\u0645\u062C \u0645\u062E\u062A\u0627\u0631 . \u064A\u0638\u0647\u0631 \u0627\u0644\u062A\u0642\u0631\u064A\u0631 \u0642\u0627\u0626\u0645\u0629\u064B \u0645\u0646 \u0623\u0645\u062B\u0644\u0629 \u0627\u0644\u0643\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0645\u062A\u0628\u0639\u0629 \u0648 \u0623\u062D\u062F\u0627\u062B\u0647\u0645 \u0627\u0644\u062A\u064A \u0644\u0645 \u062A\u062A\u0645 \u0641\u064A \u0648\u0642\u062A\u0647\u0627 . \u0627\u0644\u062A\u0635\u0641\u064A\u0629 \u0648 \u0627\u0644\u0628\u062D\u062B \u0623\u064A\u0636\u0627\u064B \u0645\u0645\u0643\u0646\u0627\u0646 . -enrollment_stats=\u0627\u062D\u0635\u0627\u0626\u064A\u0627\u062A \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -event_stats=\u0627\u062D\u0635\u0627\u0626\u064A\u0627\u062A \u0627\u0644\u062D\u062F\u062B -upcoming_event=\u0627\u0644\u062D\u062F\u062B \u0627\u0644\u062A\u0627\u0644\u064A -legend=\u0634\u0631\u0648\u062D\u0627\u062A -event_color_legend=\u0645\u0627\u0630\u0627 \u062A\u0639\u0646\u064A \u0627\u0644\u0623\u0644\u0648\u0627\u0646 -completed=\u0645\u0643\u062A\u0645\u0644 -executed=\u0645\u064F\u0646\u064E\u0641\u064E\u0630 -ontime=\u0641\u064A \u0648\u0642\u062A\u0647 -overdue=\u063A\u064A\u0631 \u0645\u0646\u062C\u0632 -skipped=\u0645\u062A\u062E\u0637\u0649 -report=\u062A\u0642\u0631\u064A\u0631 -_report=\u062A\u0642\u0631\u064A\u0631 -visit_schedule=\u062C\u062F\u0648\u0644 \u0632\u064A\u0627\u0631\u0629 -mark_for_followup=\u0627\u0634\u0631 \u0645\u0646 \u0623\u062C\u0644 \u0627\u0644\u0645\u0644\u062D\u0642 -unmark_for_followup=\u0627\u062D\u0630\u0641 \u0645\u0646 \u0627\u0644\u0645\u0644\u062D\u0642 -only_marked_for_followup=\u0641\u0642\u0637 \u0627\u0634\u0650\u0631 \u0639\u0644\u064A\u0647 \u0645\u0646 \u0623\u062C\u0644 \u0627\u0644\u0645\u0644\u062D\u0642 -registered_data=\u0642\u064A\u0645\u0629 \u0645\u0633\u062C\u0644\u0629 -no_value=\u0644\u0627 \u0642\u064A\u0645\u0629 -no_data_found=\u0644\u0645 \u062A\u0648\u062C\u062F \u0628\u064A\u0627\u0646\u0627\u062A -no_data=\u0644\u0627 \u062A\u0648\u062C\u062F \u0628\u064A\u0627\u0646\u0627\u062A -data_exists=\u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A \u0645\u062A\u0648\u0627\u062C\u062F\u0629 -data_registerd=\u0644\u0627 \u062A\u0648\u062C\u062F \u0628\u064A\u0627\u0646\u0627\u062A \u0645\u0633\u062C\u0644\u0629 -no_visit_made=\u0644\u0627 \u062A\u0648\u062C\u062F \u0632\u064A\u0627\u0631\u0627\u062A \u062A\u0627\u0645\u0629 -visit_not_made=\u0644\u0645 \u062A\u062A\u0645 \u0627\u0644\u0632\u064A\u0627\u0631\u0629 -_visit=\u0632\u064C\u0631 -visit=\u0632\u064A\u0627\u0631\u0629 -visits=\u0632\u064A\u0627\u0631\u0627\u062A -current_selections=\u0627\u0644\u0627\u062E\u062A\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u062D\u0627\u0644\u064A\u0629 -org_unit=\u0648\u062D\u062F\u0629 \u0627\u0644\u062A\u0646\u0638\u064A\u0645 -org_unit_scope=\u0645\u062F\u0649 \u0648\u062D\u062F\u0629 \u0627\u0644\u062A\u0646\u0638\u064A\u0645 -SELECTED=\u0645\u062E\u062A\u0627\u0631\\u0629 -CHILDREN=\u0627\u0644\u0623\u0637\u0641\u0627\u0644 \u0627\u0644\u0645\u062A\u0648\u0633\u0637\u0648\u0646 +tracker_reports=\u062a\u0642\u0627\u0631\u064a\u0631 \u0645\u064f\u062a\u064e\u062a\u064e\u0628\u0650\u0639\u064e\u0629 +reports=\u062a\u0642\u0627\u0631\u064a\u0631 +registration_and_data_entry=\u0627\u0644\u062a\u0633\u062c\u064a\u0644 \u0648 \u0627\u062f\u062e\u0627\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a +program_summary_report=\u062a\u0642\u0631\u064a\u0631 \u0645\u0644\u062e\u0635 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c +program_summary=\u0645\u0644\u062e\u0635 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c +program_summary_description=\u0627\u0635\u062f\u0631 \u062a\u0642\u0631\u064a\u0631\u0627\u064b \u0645\u0644\u062e\u0635\u0627\u064b \u0644\u0648\u062d\u062f\u0629 \u062a\u0646\u0638\u064a\u0645 \u0628\u0631\u0646\u0627\u0645\u062c \u0645\u062e\u0635\u0635\u0629 \u0648 \u0627\u0637\u0627\u0631\u0627\u064b \u0632\u0645\u0646\u064a\u0627\u064b . \u064a\u0642\u062f\u0645 \u0627\u0644\u062a\u0642\u0631\u064a\u0631 \u0644\u0627\u0626\u062d\u0629\u064b \u0628\u0623\u0645\u062b\u0644\u0629 \u0627\u0644\u0643\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u062a\u0628\u0639\u0629 \u0628\u0627\u0644\u0627\u0636\u0627\u0641\u0629 \u0627\u0644\u0649 \u062e\u064a\u0627\u0631 \u0627\u0644\u062a\u0639\u0645\u0642 \u0648 \u0631\u0624\u064a\u0629 \u0627\u0644\u0642\u064a\u0645 \u0627\u0644\u0641\u0639\u0644\u064a\u0629 +program_statistics_report=\u062a\u0642\u0631\u064a\u0631 \u0627\u062d\u0635\u0627\u0626\u064a\u0627\u062a \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c +program_statistics=\u0627\u062d\u0635\u0627\u0626\u064a\u0627\u062a \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c +program_statistics_description= \u0627\u0635\u062f\u0631 \u062a\u0642\u0631\u064a\u0631\u0627\u064b\u0627\u062d\u0635\u0627\u0626\u064a\u0627\u064b \u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0645\u0639\u064a\u0646 . \u064a\u062d\u0648\u064a \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0639\u0644\u0649 \u0633\u0628\u064a\u0644 \u0627\u0644\u0645\u062b\u0627\u0644 \u0648\u0635\u0641\u0627\u064b \u0639\u0627\u0645\u0627\u064b \u0639\u0646 \u0627\u0644\u0627\u0646\u0642\u0637\u0627\u0639\u0627\u062a \u0627\u0648 \u0646\u0633\u0628 \u0627\u0644\u0627\u0643\u0645\u0627\u0644 \u0641\u064a \u0627\u0637\u0627\u0631 \u0632\u0645\u0646\u064a \u0645\u0623\u062e\u0648\u0630 \u0628\u0639\u064a\u0646 \u0627\u0644\u0627\u0639\u062a\u0628\u0627\u0631 \u0641\u064a \u0648\u062d\u062f\u0629 \u062a\u0646\u0638\u064a\u0645 \u0645\u062e\u0635\u0635\u0629 +upcoming_events=\u0627\u062d\u062f\u0627\u062b \u062a\u0627\u0644\u064a\u0629 +upcoming_events_description=\u0627\u0635\u062f\u0631 \u062a\u0642\u0631\u064a\u0631\u0627\u064b \u062c\u062f\u0648\u0644\u064a\u0627\u064b \u064a\u0638\u0647\u0631 \u0641\u064a\u0647 \u0623\u0645\u062b\u0644\u0629 \u0639\u0646 \u0643\u064a\u0627\u0646\u0627\u062a \u0645\u062a\u0628\u0639\u0629 \u0648 \u0623\u062d\u062f\u0627\u062b\u0647\u0645 \u0627\u0644\u0645\u0631\u062a\u0642\u0628\u0629 \u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0648 \u0648\u0642\u062a \u0645\u062d\u062f\u062f\u064a\u0646 . \u062a\u0635\u0646\u064a\u0641 \u0627\u0644\u0628\u062d\u062b \u0648 \u0627\u0638\u0647\u0627\u0631\\u0627\u062e\u0641\u0627\u0621 \u0627\u0644\u0639\u0645\u0644\u064a\u0627\u062a \u0645\u0645\u0643\u0646\u0627\u062a \u0641\u064a \u0627\u0644\u0623\u0639\u0645\u062f\u0629 +overdue_events=\u0627\u062d\u062f\u0627\u062b \u063a\u064a\u0631 \u0645\u0646\u062c\u0632\u0629 +overdue_events_description=\u0627\u0635\u062f\u0631 \u0644\u0627\u0626\u062d\u0629 \u0645\u0646 \u0623\u062d\u062f\u0627\u062b \u0644\u0628\u0631\u0646\u0627\u0645\u062c \u0645\u062e\u062a\u0627\u0631 . \u064a\u0638\u0647\u0631 \u0627\u0644\u062a\u0642\u0631\u064a\u0631 \u0642\u0627\u0626\u0645\u0629\u064b \u0645\u0646 \u0623\u0645\u062b\u0644\u0629 \u0627\u0644\u0643\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0645\u062a\u0628\u0639\u0629 \u0648 \u0623\u062d\u062f\u0627\u062b\u0647\u0645 \u0627\u0644\u062a\u064a \u0644\u0645 \u062a\u062a\u0645 \u0641\u064a \u0648\u0642\u062a\u0647\u0627 . \u0627\u0644\u062a\u0635\u0641\u064a\u0629 \u0648 \u0627\u0644\u0628\u062d\u062b \u0623\u064a\u0636\u0627\u064b \u0645\u0645\u0643\u0646\u0627\u0646 . +enrollment_stats=\u0627\u062d\u0635\u0627\u0626\u064a\u0627\u062a \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +event_stats=\u0627\u062d\u0635\u0627\u0626\u064a\u0627\u062a \u0627\u0644\u062d\u062f\u062b +upcoming_event=\u0627\u0644\u062d\u062f\u062b \u0627\u0644\u062a\u0627\u0644\u064a +legend=\u0634\u0631\u0648\u062d\u0627\u062a +event_color_legend=\u0645\u0627\u0630\u0627 \u062a\u0639\u0646\u064a \u0627\u0644\u0623\u0644\u0648\u0627\u0646 +completed=\u0645\u0643\u062a\u0645\u0644 +executed=\u0645\u064f\u0646\u064e\u0641\u064e\u0630 +ontime=\u0641\u064a \u0648\u0642\u062a\u0647 +overdue=\u063a\u064a\u0631 \u0645\u0646\u062c\u0632 +skipped=\u0645\u062a\u062e\u0637\u0649 +report=\u062a\u0642\u0631\u064a\u0631 +_report=\u062a\u0642\u0631\u064a\u0631 +visit_schedule=\u062c\u062f\u0648\u0644 \u0632\u064a\u0627\u0631\u0629 +mark_for_followup=\u0627\u0634\u0631 \u0645\u0646 \u0623\u062c\u0644 \u0627\u0644\u0645\u0644\u062d\u0642 +unmark_for_followup=\u0627\u062d\u0630\u0641 \u0645\u0646 \u0627\u0644\u0645\u0644\u062d\u0642 +only_marked_for_followup=\u0641\u0642\u0637 \u0627\u0634\u0650\u0631 \u0639\u0644\u064a\u0647 \u0645\u0646 \u0623\u062c\u0644 \u0627\u0644\u0645\u0644\u062d\u0642 +registered_data=\u0642\u064a\u0645\u0629 \u0645\u0633\u062c\u0644\u0629 +no_value=\u0644\u0627 \u0642\u064a\u0645\u0629 +no_data_found=\u0644\u0645 \u062a\u0648\u062c\u062f \u0628\u064a\u0627\u0646\u0627\u062a +no_data=\u0644\u0627 \u062a\u0648\u062c\u062f \u0628\u064a\u0627\u0646\u0627\u062a +data_exists=\u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0645\u062a\u0648\u0627\u062c\u062f\u0629 +data_registerd=\u0644\u0627 \u062a\u0648\u062c\u062f \u0628\u064a\u0627\u0646\u0627\u062a \u0645\u0633\u062c\u0644\u0629 +no_visit_made=\u0644\u0627 \u062a\u0648\u062c\u062f \u0632\u064a\u0627\u0631\u0627\u062a \u062a\u0627\u0645\u0629 +visit_not_made=\u0644\u0645 \u062a\u062a\u0645 \u0627\u0644\u0632\u064a\u0627\u0631\u0629 +_visit=\u0632\u064c\u0631 +visit=\u0632\u064a\u0627\u0631\u0629 +visits=\u0632\u064a\u0627\u0631\u0627\u062a +current_selections=\u0627\u0644\u0627\u062e\u062a\u064a\u0627\u0631\u0627\u062a \u0627\u0644\u062d\u0627\u0644\u064a\u0629 +org_unit=\u0648\u062d\u062f\u0629 \u0627\u0644\u062a\u0646\u0638\u064a\u0645 +org_unit_scope=\u0645\u062f\u0649 \u0648\u062d\u062f\u0629 \u0627\u0644\u062a\u0646\u0638\u064a\u0645 +SELECTED=\u0645\u062e\u062a\u0627\u0631\\u0629 +CHILDREN=\u0627\u0644\u0623\u0637\u0641\u0627\u0644 \u0627\u0644\u0645\u062a\u0648\u0633\u0637\u0648\u0646 DESCENDANTS=\u0643\u0644 \u0627\u0644\u0623\u0637\u0641\u0627\u0644 -ACCESSIBLE=\u0627\u0644\u0643\u0644 \u064A\u0645\u0643\u0646 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u064A\u0647 -data_element=\u0639\u0646\u0635\u0631 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A -value=\u0642\u064A\u0645\u0629 -provided_elsewhere=\u0645\u0632\u0648\u062F\u0629 \u0628\u0645\u0643\u0627\u0646 \u0622\u062E\u0631 -expand=\u0648\u0633\u0650\u0639\\u0645\u062F\u0650\u062F -collapse=\u0627\u0646\u0647\u064A\u0627\u0631 -show_hide_columns=\u0627\u0638\u0647\u0631\\u0627\u062E\u0641\u0650 \u0623\u0639\u0645\u062F\u0629 -select_columns_to_show=\u0627\u062E\u062A\u0631 \u0623\u0639\u0645\u062F\u0629 \u0644\u064A\u062A\u0645 \u0627\u0638\u0647\u0627\u0631\u0647\u0627 -show_hide_widgets=\u0627\u0638\u0647\u0631\\u0627\u062E\u0641\u0650 \u0627\u0644\u062A\u0637\u0628\u064A\u0642\u0627\u062A \u0627\u0644\u0645\u0635\u063A\u0631\u0629 -select_widgets_to_show=\u0627\u062E\u062A\u0631 \u0627\u0644\u062A\u0637\u0628\u064A\u0642\u0627\u062A \u0627\u0644\u0645\u0635\u063A\u0631\u0629 \u0644\u064A\u062A\u0645 \u0625\u0638\u0647\u0627\u0631\u0647\u0627 -close=\u0627\u063A\u0644\u0627\u0642 +ACCESSIBLE=\u0627\u0644\u0643\u0644 \u064a\u0645\u0643\u0646 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u064a\u0647 +data_element=\u0639\u0646\u0635\u0631 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a +value=\u0642\u064a\u0645\u0629 +provided_elsewhere=\u0645\u0632\u0648\u062f\u0629 \u0628\u0645\u0643\u0627\u0646 \u0622\u062e\u0631 +expand=\u0648\u0633\u0650\u0639\\u0645\u062f\u0650\u062f +collapse=\u0627\u0646\u0647\u064a\u0627\u0631 +show_hide_columns=\u0627\u0638\u0647\u0631\\u0627\u062e\u0641\u0650 \u0623\u0639\u0645\u062f\u0629 +select_columns_to_show=\u0627\u062e\u062a\u0631 \u0623\u0639\u0645\u062f\u0629 \u0644\u064a\u062a\u0645 \u0627\u0638\u0647\u0627\u0631\u0647\u0627 +show_hide_widgets=\u0627\u0638\u0647\u0631\\u0627\u062e\u0641\u0650 \u0627\u0644\u062a\u0637\u0628\u064a\u0642\u0627\u062a \u0627\u0644\u0645\u0635\u063a\u0631\u0629 +select_widgets_to_show=\u0627\u062e\u062a\u0631 \u0627\u0644\u062a\u0637\u0628\u064a\u0642\u0627\u062a \u0627\u0644\u0645\u0635\u063a\u0631\u0629 \u0644\u064a\u062a\u0645 \u0625\u0638\u0647\u0627\u0631\u0647\u0627 +close=\u0627\u063a\u0644\u0627\u0642 generate=\u0627\u0646\u0634\u0627\u0621 print=\u0637\u0628\u0627\u0639\u0629 -excel_export=\u062A\u0635\u062F\u064A\u0631 \u0627\u0643\u0633\u0644 -list_programs=\u0627\u062F\u0631\u062C \u0627\u0644\u0628\u0631\u0627\u0645\u062C -program_stage=\u0645\u0631\u062D\u0644\u0629 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062C -due_date=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u0627\u0633\u062A\u062D\u0642\u0627\u0642 -event_date=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062D\u062F\u062B -enable_rescheduling=\u062A\u0645\u0643\u064A\u0646 \u0627\u0639\u0627\u062F\u0629 \u0627\u0644\u062C\u062F\u0648\u0644\u0629 -disable_rescheduling=\u0639\u062F\u0645 \u062A\u0645\u0643\u064A\u0646 \u0627\u0639\u0627\u062F\u0629 \u0627\u0644\u062C\u062F\u0648\u0644\u0629 -show_hide_scheduling=\u0627\u0638\u0647\u0631\\u0627\u062E\u0641\u0650 \u0627\u0633\u062A\u0645\u0627\u0631\u0629 \u0627\u0644\u062C\u062F\u0648\u0644\u0629 -show_hide_messaging=\u0627\u0638\u0647\u0631\\u0627\u062E\u0641\u0650 \u0627\u0633\u062A\u0645\u0627\u0631\u0629 \u0627\u0644\u0631\u0633\u0627\u0626\u0644 +excel_export=\u062a\u0635\u062f\u064a\u0631 \u0627\u0643\u0633\u0644 +list_programs=\u0627\u062f\u0631\u062c \u0627\u0644\u0628\u0631\u0627\u0645\u062c +program_stage=\u0645\u0631\u062d\u0644\u0629 \u0627\u0644\u0628\u0631\u0646\u0627\u0645\u062c +due_date=\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0627\u0633\u062a\u062d\u0642\u0627\u0642 +event_date=\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062d\u062f\u062b +enable_rescheduling=\u062a\u0645\u0643\u064a\u0646 \u0627\u0639\u0627\u062f\u0629 \u0627\u0644\u062c\u062f\u0648\u0644\u0629 +disable_rescheduling=\u0639\u062f\u0645 \u062a\u0645\u0643\u064a\u0646 \u0627\u0639\u0627\u062f\u0629 \u0627\u0644\u062c\u062f\u0648\u0644\u0629 +show_hide_scheduling=\u0627\u0638\u0647\u0631\\u0627\u062e\u0641\u0650 \u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0627\u0644\u062c\u062f\u0648\u0644\u0629 +show_hide_messaging=\u0627\u0638\u0647\u0631\\u0627\u062e\u0641\u0650 \u0627\u0633\u062a\u0645\u0627\u0631\u0629 \u0627\u0644\u0631\u0633\u0627\u0626\u0644 messaging=\u0631\u0633\u0627\u0626\u0644 -scheduling=\u062C\u062F\u0648\u0644\u0629 -reschedule=\u0627\u0639\u0627\u062F\u0629 \u062C\u062F\u0648\u0644\u0629 -rescheduling=\u0627\u0639\u062F \u062C\u062F\u0648\u0644\u0629 -scheduling_messaging=\u0627\u0644\u062C\u062F\u0648\u0644\u0629 \u0648 \u0627\u0644\u0631\u0633\u0627\u0626\u0644 -not_yet_enrolled_scheduling=\u063A\u064A\u0631 \u0645\u0633\u062C\u0644 \u0627\u0644\u0649 \u0627\u0644\u0644\u0622\u0646 . \u0627\u0644\u062C\u062F\u0648\u0644\u0629 \u063A\u064A\u0631 \u0645\u0645\u0643\u0646\u0629 -schedule_details=\u062A\u0641\u0627\u0635\u064A\u0644 \u0627\u0644\u062C\u062F\u0648\u0644 -no_event_to_schedule=\u0644\u0627 \u062A\u0648\u062C\u062F \u0623\u062D\u062F\u0627\u062B \u0644\u062C\u062F\u0648\u0644\u062A\u0647\u0627 -enroll=\u0633\u062C\u064D\u0644 -new_enrollment=\u062A\u0633\u062C\u0628\u0644 \u062C\u062F\u064A\u062F -start_date=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -end_date=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u0627\u0646\u062A\u0647\u0627\u0621 +scheduling=\u062c\u062f\u0648\u0644\u0629 +reschedule=\u0627\u0639\u0627\u062f\u0629 \u062c\u062f\u0648\u0644\u0629 +rescheduling=\u0627\u0639\u062f \u062c\u062f\u0648\u0644\u0629 +scheduling_messaging=\u0627\u0644\u062c\u062f\u0648\u0644\u0629 \u0648 \u0627\u0644\u0631\u0633\u0627\u0626\u0644 +not_yet_enrolled_scheduling=\u063a\u064a\u0631 \u0645\u0633\u062c\u0644 \u0627\u0644\u0649 \u0627\u0644\u0644\u0622\u0646 . \u0627\u0644\u062c\u062f\u0648\u0644\u0629 \u063a\u064a\u0631 \u0645\u0645\u0643\u0646\u0629 +schedule_details=\u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u062c\u062f\u0648\u0644 +no_event_to_schedule=\u0644\u0627 \u062a\u0648\u062c\u062f \u0623\u062d\u062f\u0627\u062b \u0644\u062c\u062f\u0648\u0644\u062a\u0647\u0627 +enroll=\u0633\u062c\u064d\u0644 +new_enrollment=\u062a\u0633\u062c\u0628\u0644 \u062c\u062f\u064a\u062f +start_date=\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +end_date=\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0627\u0646\u062a\u0647\u0627\u0621 from=\u0645\u0646 to=\u0627\u0644\u0649 -exact_date=\u0627\u0644\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062F\u0642\u064A\u0642 -exact_value=\u0627\u0644\u0642\u064A\u0645\u0629 \u0627\u0644\u062F\u0642\u064A\u0642\u0629 -EQ=\u0645\u062A\u0633\u0627\u0648\u064A\u0627\u0646 \ \u0645\u062A\u0633\u0627\u0648\u064A\u0648\u0646 -GT=\u0623\u0643\u062B\u0631 \u0645\u0646 -GE=\u0623\u0643\u062B\u0631 \u0645\u0646 \u0627\u0644\u0645\u0633\u0627\u0648\u064A +exact_date=\u0627\u0644\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062f\u0642\u064a\u0642 +exact_value=\u0627\u0644\u0642\u064a\u0645\u0629 \u0627\u0644\u062f\u0642\u064a\u0642\u0629 +EQ=\u0645\u062a\u0633\u0627\u0648\u064a\u0627\u0646 \ \u0645\u062a\u0633\u0627\u0648\u064a\u0648\u0646 +GT=\u0623\u0643\u062b\u0631 \u0645\u0646 +GE=\u0623\u0643\u062b\u0631 \u0645\u0646 \u0627\u0644\u0645\u0633\u0627\u0648\u064a LT=\u0623\u0642\u0644 \u0645\u0646 -LE=\u0623\u0642\u0644 \u0645\u0646 \u0627\u0644\u0645\u0633\u0627\u0648\u064A -NE=\u063A\u064A\u0631 \u0645\u0633\u0627\u0648\u064D -IS=\u064A\u0643\u0648\u0646 +LE=\u0623\u0642\u0644 \u0645\u0646 \u0627\u0644\u0645\u0633\u0627\u0648\u064a +NE=\u063a\u064a\u0631 \u0645\u0633\u0627\u0648\u064d +IS=\u064a\u0643\u0648\u0646 RANGE=\u0646\u0637\u0627\u0642 -like=\u064A\u0634\u0628\u0647 -not_like=\u0644\u0627 \u064A\u0634\u0628\u0647 -boolean=\u0646\u0638\u0627\u0645 \u0627\u0644\u0639\u062F \u0627\u0644\u062B\u0646\u0627\u0626\u064A +like=\u064a\u0634\u0628\u0647 +not_like=\u0644\u0627 \u064a\u0634\u0628\u0647 +boolean=\u0646\u0638\u0627\u0645 \u0627\u0644\u0639\u062f \u0627\u0644\u062b\u0646\u0627\u0626\u064a yes=\u0645\u0648\u0627\u0641\u0642 -no=\u063A\u064A\u0631 \u0645\u0648\u0627\u0641\u0642 -records=\u0633\u062C\u0644\u0627\u062A -record=\u0633\u062C\u0644 -_record=\u0633\u062C\u0650\u0644 -_records=\u0633\u062C\u0644\u0627\u062A +no=\u063a\u064a\u0631 \u0645\u0648\u0627\u0641\u0642 +records=\u0633\u062c\u0644\u0627\u062a +record=\u0633\u062c\u0644 +_record=\u0633\u062c\u0650\u0644 +_records=\u0633\u062c\u0644\u0627\u062a found=\u0623\u0633\u0650\u0633 -move_to_selected=\u0627\u0646\u0642\u0644 \u0644\u0644\u0645\u062E\u062A\u0627\u0631/\u0629 -move_all_to_selected=\u0627\u0646\u0642\u0644 \u0627\u0644\u062C\u0645\u064A\u0639 \u0644\u0644\u0645\u062E\u062A\u0627\u0631/\u0629 -new=\u062C\u062F\u064A\u062F -add_new=\u0627\u0636\u0641 \u062C\u062F\u064A\u062F\u0627\u064B -register_new=\u0633\u062C\u0650\u0644 \u062C\u062F\u064A\u062F\u0627\u064B -registration=\u0627\u0644\u062A\u0633\u062C\u064A\u0644 -registration_date=\u062A\u0627\u0631\u064A\u062E \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -register=\u062A\u0633\u062C\u064A\u0644 -_register=\u0633\u062C\u0650\u0644 -registration_error=\u062E\u0637\u0623 \u0641\u064A \u0627\u0644\u062A\u0633\u062C\u064A\u0644 -update_error=\u062E\u0637\u0627\u064B \u0641\u064A \u0627\u0644\u062A\u062D\u062F\u064A\u062B -event_creation_error=\u062E\u0637\u0623 \u0641\u064A \u0627\u0646\u0634\u0627\u0621 \u0627\u0644\u062D\u062F\u062B -relationship_error=\u062E\u0637\u0627\u064B \u0641\u064A \u0645\u0647\u0645\u0629 / \u0648\u0638\u064A\u0641\u0629 \u0627\u0644\u0639\u0644\u0627\u0642\u0629 -event_orgunit_name=\u0648\u062D\u062F\u0629 \u0627\u0644\u062A\u0646\u0638\u064A\u0645 +move_to_selected=\u0627\u0646\u0642\u0644 \u0644\u0644\u0645\u062e\u062a\u0627\u0631/\u0629 +move_all_to_selected=\u0627\u0646\u0642\u0644 \u0627\u0644\u062c\u0645\u064a\u0639 \u0644\u0644\u0645\u062e\u062a\u0627\u0631/\u0629 +new=\u062c\u062f\u064a\u062f +add_new=\u0627\u0636\u0641 \u062c\u062f\u064a\u062f\u0627\u064b +register_new=\u0633\u062c\u0650\u0644 \u062c\u062f\u064a\u062f\u0627\u064b +registration=\u0627\u0644\u062a\u0633\u062c\u064a\u0644 +registration_date=\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +register=\u062a\u0633\u062c\u064a\u0644 +_register=\u0633\u062c\u0650\u0644 +registration_error=\u062e\u0637\u0623 \u0641\u064a \u0627\u0644\u062a\u0633\u062c\u064a\u0644 +update_error=\u062e\u0637\u0627\u064b \u0641\u064a \u0627\u0644\u062a\u062d\u062f\u064a\u062b +event_creation_error=\u062e\u0637\u0623 \u0641\u064a \u0627\u0646\u0634\u0627\u0621 \u0627\u0644\u062d\u062f\u062b +relationship_error=\u062e\u0637\u0627\u064b \u0641\u064a \u0645\u0647\u0645\u0629 / \u0648\u0638\u064a\u0641\u0629 \u0627\u0644\u0639\u0644\u0627\u0642\u0629 +event_orgunit_name=\u0648\u062d\u062f\u0629 \u0627\u0644\u062a\u0646\u0638\u064a\u0645 category=\u0641\u0626\u0629 -entity_type=\u0646\u0648\u0639 \u0627\u0644\u0643\u064A\u0627\u0646 -save=\u0627\u062D\u0641\u0638 -save_and_add_new=\u0627\u062D\u0641\u0638 \u0648 \u0627\u0636\u0641 \u062C\u062F\u064A\u062F\u0627\u064B -save_and_go_back=\u0627\u062D\u0641\u0638 \u0648 \u0627\u0631\u062C\u0639 \u0644\u0644\u062E\u0644\u0641 -save_and_continue=\u0627\u062D\u0641\u0638 \u0648 \u0623\u0643\u0645\u0644 -save_relationship=\u0627\u062D\u0641\u0638 \u0627\u0644\u0639\u0644\u0627\u0642\u0629 -go_back=\u0627\u0631\u062C\u0639 \u0644\u0644\u062E\u0644\u0641 -cancel=\u0627\u0644\u063A\u0650 -are_you_sure_to_delete_enrollment=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u062D\u0630\u0641 \u0639\u0645\u0644\u064A\u0629 \u0627\u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u0645\u062E\u062A\u0627\u0631\u0629 \u061F -are_you_sure_to_complete_enrollment=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u0627\u0643\u0645\u0627\u0644 \u0639\u0645\u0644\u064A\u0629 \u0627\u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u0645\u062E\u062A\u0627\u0631\u0629 \u061F -are_you_sure_to_terminate_enrollment=\u0647\u0644 \u0627\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u0627\u0646\u0647\u0627\u0621 \u0639\u0645\u0644\u064A\u0629 \u0627\u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u0645\u062E\u062A\u0627\u0631\u0629 \u061F -are_you_sure_to_delete_event=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u062D\u0630\u0641 \u0627\u0644\u062D\u062F\u062B \u0627\u0644\u0645\u062E\u062A\u0627\u0631 \u061F -are_you_sure_to_complete_event=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u0627\u0643\u0645\u0627\u0644 \u0627\u0644\u062D\u062F\u062B \u0627\u0644\u0645\u062E\u062A\u0627\u0631 \u061F -are_you_sure_to_incomplete_event=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u0639\u062F\u0645 \u0627\u0643\u0645\u0627\u0644 \u0627\u0644\u062D\u062F\u062B \u0627\u0644\u0645\u062E\u062A\u0627\u0631 \u061F -are_you_sure_to_skip_event=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u062A\u062E\u0637\u064A \u0627\u0644\u062D\u062F\u062B \u0627\u0644\u0645\u062E\u062A\u0627\u0631 \u061F -are_you_sure_to_unskip_event=\u0647\u0644 \u0623\u0646\u062A \u0645\u062A\u0623\u0643\u062F \u0645\u0646 \u0623\u0646\u0643 \u062A\u0631\u063A\u0628 \u0641\u064A \u062C\u062F\u0648\u0644\u0629 \u0627\u0644\u062D\u062F\u062B \u0627\u0644\u0645\u062E\u062A\u0627\u0631 \u0644\u0644\u0633\u0627\u0628\u0642 \u061F -more=\u0645\u0632\u064A\u062F -under_construction=\u0645\u0627\u0632\u0627\u0644 \u0642\u064A\u062F \u0627\u0644\u0627\u0646\u0634\u0627\u0621 -advanced_search=\u0628\u062D\u062B \u0645\u062A\u0642\u062F\u0645 -profile=\u062A\u0634\u0643\u064A\u0644 \u062C\u0627\u0646\u0628\u064A -applications=\u0628\u0631\u0627\u0645\u062C -more_applications=\u0645\u0632\u064A\u062F \u0645\u0646 \u0627\u0644\u0628\u0631\u0627\u0645\u062C +entity_type=\u0646\u0648\u0639 \u0627\u0644\u0643\u064a\u0627\u0646 +save=\u0627\u062d\u0641\u0638 +save_and_add_new=\u0627\u062d\u0641\u0638 \u0648 \u0627\u0636\u0641 \u062c\u062f\u064a\u062f\u0627\u064b +save_and_go_back=\u0627\u062d\u0641\u0638 \u0648 \u0627\u0631\u062c\u0639 \u0644\u0644\u062e\u0644\u0641 +save_and_continue=\u0627\u062d\u0641\u0638 \u0648 \u0623\u0643\u0645\u0644 +save_relationship=\u0627\u062d\u0641\u0638 \u0627\u0644\u0639\u0644\u0627\u0642\u0629 +go_back=\u0627\u0631\u062c\u0639 \u0644\u0644\u062e\u0644\u0641 +cancel=\u0627\u0644\u063a\u0650 +are_you_sure_to_delete_enrollment=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u062d\u0630\u0641 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629 \u061f +are_you_sure_to_complete_enrollment=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u0627\u0643\u0645\u0627\u0644 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629 \u061f +are_you_sure_to_terminate_enrollment=\u0647\u0644 \u0627\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u0627\u0646\u0647\u0627\u0621 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629 \u061f +are_you_sure_to_delete_event=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u062d\u0630\u0641 \u0627\u0644\u062d\u062f\u062b \u0627\u0644\u0645\u062e\u062a\u0627\u0631 \u061f +are_you_sure_to_complete_event=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u0627\u0643\u0645\u0627\u0644 \u0627\u0644\u062d\u062f\u062b \u0627\u0644\u0645\u062e\u062a\u0627\u0631 \u061f +are_you_sure_to_incomplete_event=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u0639\u062f\u0645 \u0627\u0643\u0645\u0627\u0644 \u0627\u0644\u062d\u062f\u062b \u0627\u0644\u0645\u062e\u062a\u0627\u0631 \u061f +are_you_sure_to_skip_event=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u062a\u062e\u0637\u064a \u0627\u0644\u062d\u062f\u062b \u0627\u0644\u0645\u062e\u062a\u0627\u0631 \u061f +are_you_sure_to_unskip_event=\u0647\u0644 \u0623\u0646\u062a \u0645\u062a\u0623\u0643\u062f \u0645\u0646 \u0623\u0646\u0643 \u062a\u0631\u063a\u0628 \u0641\u064a \u062c\u062f\u0648\u0644\u0629 \u0627\u0644\u062d\u062f\u062b \u0627\u0644\u0645\u062e\u062a\u0627\u0631 \u0644\u0644\u0633\u0627\u0628\u0642 \u061f +more=\u0645\u0632\u064a\u062f +under_construction=\u0645\u0627\u0632\u0627\u0644 \u0642\u064a\u062f \u0627\u0644\u0627\u0646\u0634\u0627\u0621 +advanced_search=\u0628\u062d\u062b \u0645\u062a\u0642\u062f\u0645 +profile=\u062a\u0634\u0643\u064a\u0644 \u062c\u0627\u0646\u0628\u064a +applications=\u0628\u0631\u0627\u0645\u062c +more_applications=\u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u0628\u0631\u0627\u0645\u062c settings=\u0636\u0628\u0637 -account=\u062D\u0633\u0627\u0628 -help=\u0645\u0633\u0627\u0639\u062F\u0629 -log_out=\u062A\u0633\u062C\u064A\u0644 \u062E\u0631\u0648\u062C -about_dhis2=\u062D\u0648\u0644 DHIS 2 +account=\u062d\u0633\u0627\u0628 +help=\u0645\u0633\u0627\u0639\u062f\u0629 +log_out=\u062a\u0633\u062c\u064a\u0644 \u062e\u0631\u0648\u062c +about_dhis2=\u062d\u0648\u0644 DHIS 2 === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html 2015-06-02 12:25:03 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html 2015-06-10 11:55:41 +0000 @@ -114,6 +114,7 @@ + === 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-10 11:58:22 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js 2015-06-10 13:45:11 +0000 @@ -10,7 +10,7 @@ var store = new dhis2.storage.Store({ name: "dhis2tc", adapters: [dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter], - objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels'] + objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels', 'programRuleVariables', 'programRules', 'programRuleActions'] }); return{ currentStore: store @@ -1065,6 +1065,128 @@ }; }) + /* 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; + }, + + getProgramStageRules : function(programUid, programStageUid){ + var def = $q.defer(); + + TCStorageService.currentStore.open().done(function(){ + TCStorageService.currentStore.getAll('programRules').done(function(rules){ + TCStorageService.currentStore.getAll('programRuleActions').done(function(actions){ + //The hash will serve as a direct-lookup for linking the actions to rules later. + var programRulesHash = {}; + //The array will ultimately be returned to the caller. + 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) { + rule.actions = []; + programRulesHash[rule.id] = rule; + programRulesArray.push(rule); + } + } + }); + + //Loop through and attach all actions to the correct rules: + angular.forEach(actions, function(action){ + if(programRulesHash[action.programRule.id]) + { + programRulesHash[action.programRule.id].actions.push(action); + } + }); + + $rootScope.$apply(function(){ + def.resolve(programRulesArray); + }); + }); + }); + }); + + 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){ @@ -1650,5 +1772,476 @@ } return event; } + }; +}) + +/* service for building variables based on the data in users fields */ +.service('VariableService', function($rootScope,$q,TrackerRuleVariableFactory,$filter,orderByFilter,$log){ + return { + getVariables: function($scope) { + var thePromisedVariables = $q.defer(); + var variables = []; + + $scope.pushVariable = function(variablename, variablevalue, variabletype, variablefound) { + //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; + } + else { + variablevalue = false; + } + } + else if(variabletype === "int" || variabletype === "number") { + variablevalue = Number(variablevalue); + } + else{ + $log.warn("unknown datatype:" + variabletype); + } + + + //Make sure that the variablevalue does not contain a dollar sign anywhere + //- this would potentially mess up later use of the variable: +// if(angular.isDefined(variablevalue) +// && variablevalue !== null +// && variablevalue.indexOf("$") !== -1 ) { +// variablevalue = variablevalue.replace(/\\$/,""); +// } + + //TODO: + //Also clean away instructions that might be erroneusly evalutated in javascript + + variables.push({variablename:variablename, + variablevalue:variablevalue, + variabletype:variabletype, + hasValue:variablefound + }); + }; + + TrackerRuleVariableFactory.getProgramRuleVariables($scope.currentEvent.program).then(function(programVariables){ + + // The following section will need a different implementation for event capture: + var allEventsSorted = []; + var currentEvent = $scope.currentEvent; + var eventsSortedPerProgramStage = []; + + for(var key in $scope.eventsByStage){ + if($scope.eventsByStage.hasOwnProperty(key)){ + eventsSortedPerProgramStage[key] = []; + angular.forEach($scope.eventsByStage[key], function(event){ + allEventsSorted.push(event); + eventsSortedPerProgramStage[key].push(event); + }); + eventsSortedPerProgramStage[key] = orderByFilter(eventsSortedPerProgramStage[key], '-sortingDate').reverse(); + } + } + allEventsSorted = orderByFilter(allEventsSorted, '-sortingDate').reverse(); + + var allDes = {}; + angular.forEach($scope.programStages, function(programStage){ + angular.forEach(programStage.programStageDataElements, function(dataElement) { + allDes[dataElement.dataElement.id] = dataElement; + }); + }); + //End of region that neeeds specific implementation for event capture + + angular.forEach(programVariables, function(programVariable) { + var valueFound = false; + if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE"){ + if(programVariable.programStage) { + angular.forEach(eventsSortedPerProgramStage[programVariable.programStage.id], function(event) { + if(angular.isDefined(event[programVariable.dataElement.id]) + && event[programVariable.dataElement.id] !== null ){ + valueFound = true; + $scope.pushVariable(programVariable.name, event[programVariable.dataElement.id], allDes[programVariable.dataElement.id].dataElement.type, valueFound ); + } + }); + } else { + $log.warn("Variable id:'" + programVariable.id + "' name:'" + programVariable.name + + "' does not have a programstage defined," + + " despite that the variable has sourcetype DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE" ); + } + + } + else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_NEWEST_EVENT_PROGRAM"){ + angular.forEach(allEventsSorted, function(event) { + if(angular.isDefined(event[programVariable.dataElement.id]) + && event[programVariable.dataElement.id] !== null ){ + valueFound = true; + $scope.pushVariable(programVariable.name, event[programVariable.dataElement.id], allDes[programVariable.dataElement.id].dataElement.type, valueFound ); + } + }); + } + else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_CURRENT_EVENT"){ + if(angular.isDefined(currentEvent[programVariable.dataElement.id]) + && currentEvent[programVariable.dataElement.id] !== null ){ + valueFound = true; + $scope.pushVariable(programVariable.name, currentEvent[programVariable.dataElement.id], allDes[programVariable.dataElement.id].dataElement.type, valueFound ); + } + } + else if(programVariable.programRuleVariableSourceType === "DATAELEMENT_PREVIOUS_EVENT"){ + //Only continue checking for a value if there is more than one event. + if(allEventsSorted && allEventsSorted.length > 1) { + var previousvalue = null; + var currentEventPassed = false; + for(var i = 0; i < allEventsSorted.length; i++) { + //Store the values as we iterate through the stages + //If the event[i] is not the current event, it is older(previous). Store the previous value if it exists + if(!currentEventPassed && allEventsSorted[i] !== currentEvent && + angular.isDefined(allEventsSorted[i][programVariable.dataElement.id])) { + previousvalue = allEventsSorted[i][programVariable.dataElement.id]; + valueFound = true; + } + else if(allEventsSorted[i] === currentEvent) { + //We have iterated to the newest event - store the last collected variable value - if any is found: + if(valueFound) { + $scope.pushVariable(programVariable.name, previousvalue, allDes[programVariable.dataElement.id].dataElement.type, valueFound ); + } + //Set currentEventPassed, ending the iteration: + currentEventPassed = true; + } + + } + } + } + else if(programVariable.programRuleVariableSourceType === "TEI_ATTRIBUTE"){ + angular.forEach($scope.selectedEntity.attributes , function(attribute) { + if(!valueFound) { + if(attribute.attribute === programVariable.trackedEntityAttribute.id) { + valueFound = true; + $scope.pushVariable(programVariable.name, attribute.value, attribute.type, valueFound ); + } + } + }); + } + else if(programVariable.programRuleVariableSourceType === "CALCULATED_VALUE"){ + //We won't assign the calculated variables at this step. The rules execution will calculate and assign the variable. + } + else if(programVariable.programRuleVariableSourceType === "NUMBEROFEVENTS_PROGRAMSTAGE"){ + var numberOfEvents = 0; + if( programVariable.programStage && eventsSortedPerProgramStage[programVariable.programStage.id] ) { + numberOfEvents = eventsSortedPerProgramStage[programVariable.programStage.id].length; + } + valueFound = true; + $scope.pushVariable(programVariable.name, numberOfEvents, 'int', valueFound ); + } + else { + //Missing handing of ruletype + $log.warn("Unknown programRuleVariableSourceType:" + programVariable.programRuleVariableSourceType); + } + + + if(!valueFound){ + //If there is still no value found, assign default value: + if(programVariable.dataElement) { + var dataElement = allDes[programVariable.dataElement.id]; + if( dataElement ) { + $scope.pushVariable(programVariable.name, "", dataElement.dataElement.type ); + } + else { + $log.warn("Variable #{" + programVariable.name + "} is linked to a dataelement that is not part of the program"); + $scope.pushVariable(programVariable.name, "", "string" ); + } + } + else { + $scope.pushVariable(programVariable.name, "", "string" ); + } + } + }); + + //add context variables: + //last parameter "valuefound" is always true for event date + $scope.pushVariable('eventdate', currentEvent.eventDate, 'date', true ); + + thePromisedVariables.resolve(variables); + }); + + return thePromisedVariables.promise; + } + }; +}) + + + +/* service for executing tracker rules and broadcasting results */ +.service('TrackerRulesExecutionService', function(TrackerRulesFactory,VariableService, $rootScope, $log, $filter, orderByFilter){ + return { + executeRules: function($scope) { + //When debugging rules, the caller should provide a variable for wether or not the rules is being debugged. + //hard coding this for now: + var debug = true; + var verbose = true; + + var variablesHash = {}; + var variablesWithValueHash = {}; + + $scope.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+}/g); + //Replace each matched variable: + angular.forEach(variablespresent, function(variablepresent) { + //First strip away any dollar signs from the variable name: + variablepresent = variablepresent.replace("#{","").replace("}",""); + + if(angular.isDefined(variablesHash[variablepresent])) { + //Replace all occurrences of the variable name(hence using regex replacement): + expression = expression.replace(new RegExp("#{" + variablepresent + "}", 'g'), + variablesHash[variablepresent]); + } + else { + $log.warn("Expression " + expression + " conains variable " + variablepresent + + " - but this variable is not defined." ); + } + + }); + } + return expression; + }; + + $scope.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] = $scope.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(variablesWithValueHash[parameters[0]]){ + 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; + }; + + $scope.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 = $scope.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 = $scope.runDhisFunctions(expression); + answer = eval(dhisfunctionsevaluated); + } + return answer; + }; + + + VariableService.getVariables($scope).then(function(variables){ + TrackerRulesFactory.getProgramStageRules($scope.selectedProgram.id, $scope.currentStage.id).then(function(rules){ + //But run rules in priority - lowest number first(priority null is last) + rules = orderByFilter(rules, 'priority'); + + //Make a variables hash to allow direct lookup: + angular.forEach(variables, function(variable) { + variablesHash[variable.variablename] = variable.variablevalue; + }); + + //Make a variables-exists/hasvalue hash to allow direct lookup: + angular.forEach(variables, function(variable) { + variablesWithValueHash[variable.variablename] = variable.hasValue; + }); + + 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 = {}; + } + + 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 = $scope.replaceVariables(expression); + } + //run expression: + ruleEffective = $scope.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.actions, function(action){ + //In case the effect-hash is not populated, add entries + if(angular.isUndefined( $rootScope.ruleeffects[action.id] )){ + $rootScope.ruleeffects[action.id] = { + id:action.id, + location:action.location, + action:action.programRuleActionType, + dataElement:action.dataElement, + content:action.content, + data:action.data, + ineffect:false + }; + } + + //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 nameWithoutDollarSign = action.data.replace('#{','').replace('}',''); + if(angular.isDefined(variablesHash[nameWithoutDollarSign])) + { + //The variable exists, and is replaced with its corresponding value + $rootScope.ruleeffects[action.id].data = + variablesHash[nameWithoutDollarSign]; + } + 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[action.id].data = $scope.replaceVariables(action.data); + //In a scenario where the data contains a complex expression, evaluate the expression to compile(calculate) the result: + $rootScope.ruleeffects[action.id].data = $scope.runExpression($rootScope.ruleeffects[action.id].data, action.data, "action:" + action.id); + } + } + + //Update the rule effectiveness if it changed in this evaluation; + if($rootScope.ruleeffects[action.id].ineffect != ruleEffective) + { + //There is a change in the rule outcome, we need to update the effect object. + updatedEffectsExits = true; + $rootScope.ruleeffects[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[action.id].action === "ASSIGNVARIABLE" && $rootScope.ruleeffects[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[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] !== $rootScope.ruleeffects[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] = $rootScope.ruleeffects[action.id].data; + } + } + }); + }); + + //Broadcast rules finished if there was any actual changes. + if(updatedEffectsExits){ + $rootScope.$broadcast("ruleeffectsupdated"); + } + } + + return true; + }); + }); + } }; }); === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js 2015-06-11 09:09:20 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js 2015-06-11 18:44:52 +0000 @@ -29,7 +29,7 @@ dhis2.tc.store = new dhis2.storage.Store({ name: 'dhis2tc', adapters: [dhis2.storage.IndexedDBAdapter, dhis2.storage.DomSessionStorageAdapter, dhis2.storage.InMemoryAdapter], - objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels'] + objectStores: ['programs', 'programStages', 'trackedEntities', 'trackedEntityForms', 'attributes', 'relationshipTypes', 'optionSets', 'programValidations', 'ouLevels', 'programRuleVariables', 'programRules', 'programRuleActions'] }); (function($) { @@ -141,6 +141,12 @@ promise = promise.then( getMetaTrackeEntityAttributes ); promise = promise.then( getTrackedEntityAttributes ); promise = promise.then( getOptionSetsForAttributes ); + promise = promise.then( getMetaProgramRuleVariables ); + promise = promise.then( getProgramRuleVariables ); + promise = promise.then( getMetaProgramRules ); + promise = promise.then( getProgramRules ); + promise = promise.then( getMetaProgramRuleActions ); + promise = promise.then( getProgramRuleActions ); promise = promise.then( getMetaProgramValidations ); promise = promise.then( getProgramValidations ); promise = promise.then( getTrackedEntityForms ); @@ -490,6 +496,335 @@ }; } +function getMetaProgramRuleActions( data ) +{ + if( !data ){ + return; + } + + var def = $.Deferred(); + + var programRuleIds = []; + _.each( _.values( data.programRules ), function ( programRule ) { + if( programRule.id ) { + programRuleIds.push( programRule.id ); + } + }); + + $.ajax({ + url: '../api/programRuleActions.json', + type: 'GET', + data:'paging=false&fields=id,programRule[id]' + }).done( function(response) { + var programRuleActions = []; + _.each( _.values( response.programRuleActions ), function ( programRuleAction ) { + if( programRuleAction && + programRuleAction.id && + programRuleAction.programRule && + programRuleAction.programRule.id && + programRuleIds.indexOf( programRuleAction.programRule.id ) !== -1) { + + programRuleActions.push( programRuleAction ); + } + }); + + def.resolve( {programRuleActions: programRuleActions, programs: data.programs} ); + + }).fail(function(){ + def.resolve( null ); + }); + + return def.promise(); +} + +function getProgramRuleActions( data ) +{ + if( !data || !data.programRuleActions ){ + return; + } + + var mainDef = $.Deferred(); + var mainPromise = mainDef.promise(); + + var def = $.Deferred(); + var promise = def.promise(); + + var builder = $.Deferred(); + var build = builder.promise(); + + _.each( _.values( data.programRuleActions ), function ( programRuleAction ) { + build = build.then(function() { + var d = $.Deferred(); + var p = d.promise(); + dhis2.tc.store.get('programRuleActions', programRuleAction.id).done(function(obj) { + if(!obj) { + promise = promise.then( getProgramRuleAction( programRuleAction.id ) ); + } + d.resolve(); + }); + + return p; + }); + }); + + build.done(function() { + def.resolve(); + + promise = promise.done( function () { + mainDef.resolve( data.programs ); + } ); + }).fail(function(){ + mainDef.resolve( null ); + }); + + builder.resolve(); + + return mainPromise; +} + +function getProgramRuleAction( id ) +{ + return function() { + return $.ajax( { + url: '../api/programRuleActions.json', + type: 'GET', + data: 'paging=false&filter=id:eq:' + id +'&fields=id,programRule[id],programRuleActionType,dataElement[id],location,content,data,' + }).done( function( response ){ + + _.each( _.values( response.programRuleActions ), function ( programRuleAction ) { + + if( programRuleAction && + programRuleAction.id && + programRuleAction.programRule && + programRuleAction.programRule.id ) { + + dhis2.tc.store.set( 'programRuleActions', programRuleAction ); + } + }); + }); + }; +} + +function getMetaProgramRuleVariables( programs ) +{ + if( !programs ){ + return; + } + + var def = $.Deferred(); + + var programIds = []; + _.each( _.values( programs ), function ( program ) { + if( program.id ) { + programIds.push( program.id ); + } + }); + + $.ajax({ + url: '../api/programRuleVariables.json', + type: 'GET', + data:'paging=false&fields=id,program[id]' + }).done( function(response) { + var programRuleVariables = []; + _.each( _.values( response.programRuleVariables ), function ( programRuleVariable ) { + if( programRuleVariable && + programRuleVariable.id && + programRuleVariable.program && + programRuleVariable.program.id && + programIds.indexOf( programRuleVariable.program.id ) !== -1) { + + programRuleVariables.push( programRuleVariable ); + } + + }); + + def.resolve( {programRuleVariables: programRuleVariables, programs: programs} ); + + }).fail(function(){ + def.resolve( null ); + }); + + return def.promise(); +} + +function getProgramRuleVariables( data ) +{ + if( !data || !data.programRuleVariables ){ + return; + } + + var mainDef = $.Deferred(); + var mainPromise = mainDef.promise(); + + var def = $.Deferred(); + var promise = def.promise(); + + var builder = $.Deferred(); + var build = builder.promise(); + + _.each( _.values( data.programRuleVariables ), function ( programRuleVariable ) { + build = build.then(function() { + var d = $.Deferred(); + var p = d.promise(); + dhis2.tc.store.get('programRuleVariables', programRuleVariable.id).done(function(obj) { + if(!obj) { + promise = promise.then( getProgramRuleVariable( programRuleVariable.id ) ); + } + d.resolve(); + }); + + return p; + }); + }); + + build.done(function() { + def.resolve(); + + promise = promise.done( function () { + mainDef.resolve( data.programs ); + } ); + }).fail(function(){ + mainDef.resolve( null ); + }); + + builder.resolve(); + + return mainPromise; +} + +function getProgramRuleVariable( id ) +{ + return function() { + return $.ajax( { + url: '../api/programRuleVariables.json', + type: 'GET', + data: 'paging=false&filter=id:eq:' + id +'&fields=id,program[id],name,programRuleVariableSourceType,trackedEntityAttribute[id],dataElement[id],programStage[id]' + }).done( function( response ){ + + _.each( _.values( response.programRuleVariables ), function ( programRuleVariable ) { + + if( programRuleVariable && + programRuleVariable.id && + programRuleVariable.program && + programRuleVariable.program.id ) { + + dhis2.tc.store.set( 'programRuleVariables', programRuleVariable ); + } + }); + }); + }; +} + +function getMetaProgramRules( programs ) +{ + if( !programs ){ + return; + } + + var def = $.Deferred(); + + var programIds = []; + _.each( _.values( programs ), function ( program ) { + if( program.id ) { + programIds.push( program.id ); + } + }); + + $.ajax({ + url: '../api/programRules.json', + type: 'GET', + data:'paging=false&fields=id,program[id]' + }).done( function(response) { + var programRules = []; + _.each( _.values( response.programRules ), function ( programRule ) { + if( programRule && + programRule.id && + programRule.program && + programRule.program.id && + programIds.indexOf( programRule.program.id ) !== -1) { + + programRules.push( programRule ); + } + + }); + + def.resolve( {programRules: programRules, programs: programs} ); + + }).fail(function(){ + def.resolve( null ); + }); + + return def.promise(); +} + +function getProgramRules( data ) +{ + if( !data || !data.programRules ){ + return; + } + + var mainDef = $.Deferred(); + var mainPromise = mainDef.promise(); + + var def = $.Deferred(); + var promise = def.promise(); + + var builder = $.Deferred(); + var build = builder.promise(); + + _.each( _.values( data.programRules ), function ( programRule ) { + build = build.then(function() { + var d = $.Deferred(); + var p = d.promise(); + dhis2.tc.store.get('programRules', programRule.id).done(function(obj) { + if(!obj) { + promise = promise.then( getProgramRule( programRule.id ) ); + } + d.resolve(); + }); + + return p; + }); + }); + + build.done(function() { + def.resolve(); + + promise = promise.done( function () { + mainDef.resolve( data ); + } ); + }).fail(function(){ + mainDef.resolve( null ); + }); + + builder.resolve(); + + return mainPromise; +} + +function getProgramRule( id ) +{ + return function() { + return $.ajax( { + url: '../api/programRules.json', + type: 'GET', + data: 'paging=false&filter=id:eq:' + id +'&fields=id,name,description,condition,program[id],programstage[id],priority' + }).done( function( response ){ + + _.each( _.values( response.programRules ), function ( programRule ) { + + if( programRule && + programRule.id && + programRule.program && + programRule.program.id ) { + + dhis2.tc.store.set( 'programRules', programRule ); + } + }); + }); + }; +} + function getMetaProgramValidations( programs ) { if( !programs ){ === modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css' --- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css 2015-06-02 12:25:03 +0000 +++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css 2015-06-10 11:55:41 +0000 @@ -384,6 +384,33 @@ margin-left: 5px; } +.info-container { + display: inline-block; + height:60px; + opacity: 1.0; + white-space: normal; + text-align: center; + border: 1px solid #aaa; + border-radius: 4px; + padding:0px; + margin-right: 10px +} +.info-container-text{ + font-weight: bold; + padding: 5px 10px; + margin:0px; +} +.info-container-heading { + font-weight: normal; + padding: 5px 10px; + margin:0px; + background-color: #f5f5f5; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} + + /*----------------------------------------------------------------------------*/ /* Tracked entity /*----------------------------------------------------------------------------*/ @@ -426,8 +453,6 @@ .dashboard-widget-container { height: auto; - overflow-x:auto; - overflow-y:auto; } .widget-link {