From ac479726ac98a1e3d926e485e271ad69d8c0c0d2 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 17:24:59 +0300 Subject: [PATCH 01/12] Introduce hedley_stats_run_node_query_in_batches() and use for every stats query [ci skip] --- .../custom/hedley_stats/hedley_stats.module | 90 ++++++------------- 1 file changed, 26 insertions(+), 64 deletions(-) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 79327d35f9..11104aefca 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -455,9 +455,7 @@ function hedley_stats_get_acute_illness_data($health_center_id) { hedley_general_join_field_to_query($query, 'node', $field, FALSE); } - $result = $query - ->execute() - ->fetchAllAssoc('nid'); + $result = hedley_stats_run_node_query_in_batches($query); $items = []; // Prepare illnesses data to be consumed by client side. @@ -533,9 +531,7 @@ function hedley_stats_get_acute_illness_data($health_center_id) { $query->groupBy('node.nid'); - $result = $query - ->execute() - ->fetchAllAssoc('nid'); + $result = hedley_stats_run_node_query_in_batches($query); // Populate data of the encounters. foreach ($result as $row) { @@ -604,9 +600,7 @@ function hedley_stats_get_prenatal_data($health_center_id) { // Get only participants of Antenatal type. $query->condition('field_encounter_type.field_encounter_type_value', HEDLEY_STATS_PRENATAL_ENCOUNTER_TYPE); - $result = $query - ->execute() - ->fetchAllAssoc('nid'); + $result = hedley_stats_run_node_query_in_batches($query); if (empty($result)) { return []; @@ -649,9 +643,7 @@ function hedley_stats_get_prenatal_data($health_center_id) { $query->groupBy('node.nid'); - $result = $query - ->execute() - ->fetchAllAssoc('nid'); + $result = hedley_stats_run_node_query_in_batches($query); foreach ($result as $row) { $items[$row->field_individual_participant]['encounters'][] = [ @@ -732,9 +724,7 @@ function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, // defined period. $query->condition('field_expected.field_expected_value2', $date['start'], '>'); - $result = $query - ->execute() - ->fetchAllAssoc('nid'); + $result = hedley_stats_run_node_query_in_batches($query); $items = []; foreach (hedley_stats_get_all_clinic_types() as $clinic_type) { @@ -794,9 +784,7 @@ function hedley_stats_get_children_beneficiaries_individual_stats($health_center $query->condition('field_encounter_type.field_encounter_type_value', 'nutrition'); - $result = $query - ->execute() - ->fetchAll(); + $result = hedley_stats_run_node_query_in_batches($query); $items = []; foreach ($result as $row) { @@ -865,9 +853,7 @@ function hedley_stats_get_family_planning_stats_by_period($health_center_id, $pe $query->groupBy('node.nid'); $query->addExpression('GROUP_CONCAT(field_family_planning_signs.field_family_planning_signs_value)', 'signs'); - $result = $query - ->execute() - ->fetchAllAssoc('nid'); + $result = hedley_stats_run_node_query_in_batches($query); // Prepare data to be consumed by client side. foreach ($result as &$row) { @@ -1512,37 +1498,8 @@ function hedley_stats_get_nutrition_measurements_for_clinic_type_grouped_by_pers // Filter by clinic type. $query->condition('field_group_type.field_group_type_value', $clinic_type); - $query->orderBy('node.nid'); - - $result = []; - $nid = 0; - $batch = 1000; - - // This query can produce, 30K, 50K, or even 100K rows of result. - // This size may cause 'out of memory' exception. - // Therefore, we run this query with batches, accumulation - // the result with every batch. - while (TRUE) { - $batch_query = clone $query; - // We want to get results for nodes we did not process before. - $batch_query->condition('nid', $nid, '>'); - - $batch_result = $batch_query - ->range(0, $batch) - ->execute() - ->fetchAllAssoc('nid'); - - if (empty($batch_result)) { - // There's no more results, so we know that no more - // batches are needed, and we can exit the WHILE loop. - break; - } - // Accumulate results. - $result = array_merge($result, $batch_result); - // Locate latest node processed, for the next batch. - $nid = end($batch_result)->nid; - } + $result = hedley_stats_run_node_query_in_batches($query); // Group measurements by person. $people = []; @@ -1594,11 +1551,27 @@ function hedley_stats_get_nutrition_measurements_for_individual_encounters_group hedley_general_join_field_to_query($query, 'node', 'field_zscore_length', FALSE); hedley_general_join_field_to_query($query, 'node', 'field_zscore_bmi', FALSE); + $result = hedley_stats_run_node_query_in_batches($query); + + // Group measurements by person. + $people = []; + foreach ($result as $measurement) { + // Get fields for current node type. + $measurement_fields = $node_types[$measurement->type]; + + foreach ($measurement_fields as $measurement_field) { + $people[$measurement->field_person][$measurement->type][$measurement->field_date_measured][$measurement_field] = $measurement->{$measurement_field}; + } + } + + return $people; +} + +function hedley_stats_run_node_query_in_batches($query, $batch = 5000) { $query->orderBy('node.nid'); $result = []; $nid = 0; - $batch = 1000; // This query can produce, 30K, 50K, or even 100K rows of result. // This size may cause 'out of memory' exception. @@ -1621,18 +1594,7 @@ function hedley_stats_get_nutrition_measurements_for_individual_encounters_group $nid = end($batch_result)->nid; } - // Group measurements by person. - $people = []; - foreach ($result as $measurement) { - // Get fields for current node type. - $measurement_fields = $node_types[$measurement->type]; - - foreach ($measurement_fields as $measurement_field) { - $people[$measurement->field_person][$measurement->type][$measurement->field_date_measured][$measurement_field] = $measurement->{$measurement_field}; - } - } - - return $people; + return $result; } /** From 541d6a8cf8bcd14591e3044c4013f4f24b26d116 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 19:54:18 +0300 Subject: [PATCH 02/12] Clear statistics data on logout --- client/src/elm/App/Update.elm | 6 +++++- client/src/elm/Backend/Model.elm | 2 ++ client/src/elm/Backend/Update.elm | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/client/src/elm/App/Update.elm b/client/src/elm/App/Update.elm index fd272e8eee..ceee80ea8c 100644 --- a/client/src/elm/App/Update.elm +++ b/client/src/elm/App/Update.elm @@ -582,7 +582,11 @@ update msg model = ( [ TryPinCode code ], [] ) Pages.PinCode.Model.Logout -> - ( [ SetLoggedIn NotAsked, SetHealthCenter Nothing, SetVillage Nothing ] + ( [ SetLoggedIn NotAsked + , MsgIndexedDb Backend.Model.HandleLogout + , SetHealthCenter Nothing + , SetVillage Nothing + ] , [ cachePinCode "", cacheHealthCenter "", cacheVillage "" ] ) diff --git a/client/src/elm/Backend/Model.elm b/client/src/elm/Backend/Model.elm index af3bee917c..4a4bbe988a 100644 --- a/client/src/elm/Backend/Model.elm +++ b/client/src/elm/Backend/Model.elm @@ -320,6 +320,8 @@ type MsgIndexedDb | HandlePostedNutritionEncounter IndividualEncounterParticipantId (WebData ( NutritionEncounterId, NutritionEncounter )) | HandlePostedAcuteIllnessEncounter IndividualEncounterParticipantId (WebData ( AcuteIllnessEncounterId, AcuteIllnessEncounter )) | HandlePostedHomeVisitEncounter IndividualEncounterParticipantId (WebData ( HomeVisitEncounterId, HomeVisitEncounter )) + -- Operations we may want to perform when logout is clicked. + | HandleLogout -- Process some revisions we've received from the backend. In some cases, -- we can update our in-memory structures appropriately. In other cases, we -- can set them to `NotAsked` and let the "fetch" mechanism re-fetch them. diff --git a/client/src/elm/Backend/Update.elm b/client/src/elm/Backend/Update.elm index 3b4d38dc20..dfd2d4d955 100644 --- a/client/src/elm/Backend/Update.elm +++ b/client/src/elm/Backend/Update.elm @@ -112,6 +112,25 @@ updateIndexedDb language currentDate currentTime zscores nurseId healthCenterId ( model, Cmd.none, [] ) in case msg of + HandleLogout -> + let + -- On logout we want to clear the statistics dashboards loaded + -- for health center. + -- We do this to maintain proper loading rutine when switching + -- between nurse and chw. + updatedComputedDashboards = + Maybe.map + (\healthCenterId_ -> + Dict.remove healthCenterId_ model.computedDashboards + ) + healthCenterId + |> Maybe.withDefault model.computedDashboards + in + ( { model | computedDashboards = updatedComputedDashboards } + , Cmd.none + , [] + ) + FetchChildMeasurements childId -> ( { model | childMeasurements = Dict.insert childId Loading model.childMeasurements } , sw.get childMeasurementListEndpoint childId From 61f39c3613d039b60eca99d618f508638a789424 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 20:05:25 +0300 Subject: [PATCH 03/12] Comments --- .../custom/hedley_stats/hedley_stats.module | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 11104aefca..3473dc67c3 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -1567,18 +1567,31 @@ function hedley_stats_get_nutrition_measurements_for_individual_encounters_group return $people; } +/** + * Executes query in batches, with constant number of results at each batch. + * + * Complex query can produce, 50K, 100K or even more rows of result. + * This size may cause 'out of memory' exception. + * To prevent this, we run these queries in batches. There will be more hits + * at the DB, but we don't end up running out of memory. + * + * @param SelectQuery $query + * The query to execute. + * @param int $batch + * Number of results we want to receive at each batch. Defaults to 5000. + * + * @return array + * Query accumulated result. + */ function hedley_stats_run_node_query_in_batches($query, $batch = 5000) { $query->orderBy('node.nid'); $result = []; $nid = 0; - // This query can produce, 30K, 50K, or even 100K rows of result. - // This size may cause 'out of memory' exception. - // Therefore, we run this query with batches, accumulation - // the result with every batch. while (TRUE) { $batch_query = clone $query; + // We want to get results for nodes we did not process before. $batch_query->condition('nid', $nid, '>'); $batch_result = $batch_query @@ -1587,10 +1600,14 @@ function hedley_stats_run_node_query_in_batches($query, $batch = 5000) { ->fetchAllAssoc('nid'); if (empty($batch_result)) { + // There's no more results, so we know that no more + // batches are needed, and we can exit the WHILE loop. break; } + // Accumulate result. $result = array_merge($result, $batch_result); + // Locate the latest node processed, for the next batch. $nid = end($batch_result)->nid; } From 2c219b80c4d64ac2192a2ff2b8e569b3f9ee2293 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 20:13:14 +0300 Subject: [PATCH 04/12] Satisfy coder [ci skip] --- server/hedley/modules/custom/hedley_stats/hedley_stats.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 3473dc67c3..87a0642787 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -1583,7 +1583,7 @@ function hedley_stats_get_nutrition_measurements_for_individual_encounters_group * @return array * Query accumulated result. */ -function hedley_stats_run_node_query_in_batches($query, $batch = 5000) { +function hedley_stats_run_node_query_in_batches(SelectQuery $query, $batch = 5000) { $query->orderBy('node.nid'); $result = []; From df259664275ff3a7633aa829111713660092a96a Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 23:30:09 +0300 Subject: [PATCH 05/12] A fix [ci skip] --- .../modules/custom/hedley_stats/hedley_stats.module | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 87a0642787..ab674fa051 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -459,8 +459,8 @@ function hedley_stats_get_acute_illness_data($health_center_id) { $items = []; // Prepare illnesses data to be consumed by client side. - foreach ($result as $index => $row) { - $items[$index] = [ + foreach ($result as $row) { + $items[$row->nid] = [ 'id' => $row->field_person, // Field for 'created' is added at hedley_stats_get_base_query(). 'created' => date_format(date_create($row->field_expected), 'Y-m-d'), @@ -608,8 +608,8 @@ function hedley_stats_get_prenatal_data($health_center_id) { $items = []; // Prepare data to be consumed by client side. - foreach ($result as $index => $row) { - $items[$index] = [ + foreach ($result as $row) { + $items[$row->nid] = [ 'id' => $row->field_person, // Field for 'created' is added at hedley_stats_get_base_query(). 'created' => date_format(date_create($row->field_expected), 'Y-m-d'), From a85c54fcb7fb0815c2d8327da90e393de1f00dbb Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 23:30:42 +0300 Subject: [PATCH 06/12] Reduce payload [ci skip] --- client/src/elm/Backend/Dashboard/Decoder.elm | 8 ++++---- client/src/elm/Backend/Dashboard/Encoder.elm | 8 ++++---- .../modules/custom/hedley_stats/hedley_stats.module | 7 +++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/client/src/elm/Backend/Dashboard/Decoder.elm b/client/src/elm/Backend/Dashboard/Decoder.elm index 04d3611eca..256b8977a7 100644 --- a/client/src/elm/Backend/Dashboard/Decoder.elm +++ b/client/src/elm/Backend/Dashboard/Decoder.elm @@ -124,16 +124,16 @@ decodeNutritionStatus = |> andThen (\s -> case s of - "neutral" -> + "0" -> succeed Neutral - "good_nutrition" -> + "1" -> succeed Good - "moderate_nutrition" -> + "2" -> succeed Moderate - "severe_nutrition" -> + "3" -> succeed Severe _ -> diff --git a/client/src/elm/Backend/Dashboard/Encoder.elm b/client/src/elm/Backend/Dashboard/Encoder.elm index 2b2a64bb1a..79b5d592cc 100644 --- a/client/src/elm/Backend/Dashboard/Encoder.elm +++ b/client/src/elm/Backend/Dashboard/Encoder.elm @@ -99,16 +99,16 @@ encodeNutritionStatus status = string <| case status of Neutral -> - "neutral" + "0" Good -> - "good_nutrition" + "1" Moderate -> - "moderate_nutrition" + "2" Severe -> - "severe_nutrition" + "3" encodeChildrenBeneficiariesData : Dict ProgramType (List ChildrenBeneficiariesStats) -> ( String, Value ) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index ab674fa051..fec158d060 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -18,10 +18,9 @@ define('HEDLEY_STATS_PERIOD_LAST_YEAR', 'last_year'); define('HEDLEY_STATS_PERIOD_480_DAYS', '480_days'); define('HEDLEY_STATS_PERIOD_PAST_SIX_MONTHS', 'past_six_month'); - -define('HEDLEY_STATS_SEVERE', 'severe_nutrition'); -define('HEDLEY_STATS_MODERATE', 'moderate_nutrition'); -define('HEDLEY_STATS_GOOD', 'good_nutrition'); +define('HEDLEY_STATS_GOOD', '1'); +define('HEDLEY_STATS_MODERATE', '2'); +define('HEDLEY_STATS_SEVERE', '3'); // Encounter types. define('HEDLEY_STATS_PRENATAL_ENCOUNTER_TYPE', 'antenatal'); From c567028cc17fe2a3ab50e69990b69a930b7ef9f5 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 27 Aug 2021 23:30:57 +0300 Subject: [PATCH 07/12] Drop unneeded caching --- .../modules/custom/hedley_stats/hedley_stats.module | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index fec158d060..680f16a928 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -33,7 +33,6 @@ define('HEDLEY_STATS_ACUTE_ILLNESS', 'sync_stats_acute_illness'); // Cache IDs. define('HEDLEY_STATS_SYNC_STATS_CACHE', 'sync_stats_general'); -define('HEDLEY_STATS_SYNC_MEASUREMENTS_BY_PERSON', 'sync_measurements_query_grouped_by_person'); define('HEDLEY_STATS_SYNC_SESSION_ATTENDANCE', 'sync_session_attendance_stats'); define('HEDLEY_STATS_SYNC_CHILDREN_BENEFICIARIES', 'sync_children_beneficiaries_stats'); define('HEDLEY_STATS_SYNC_FAMILY_PLANNING', 'sync_family_planning_stats'); @@ -252,7 +251,6 @@ function hedley_stats_clear_caches_for_health_center($nid, $cache_type_for_recal // Clear cache for all the periods. foreach ($periods as $period) { hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_FAMILY_PLANNING, $nid, $period); - hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_MEASUREMENTS_BY_PERSON, $nid, $period); hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_CHILDREN_BENEFICIARIES, $nid, $period); hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_CASE_MANAGEMENT, $nid, $period); } @@ -1430,13 +1428,6 @@ function hedley_stats_get_all_clinic_types() { * @throws \Exception */ function hedley_stats_get_nutrition_measurements_grouped_by_person($health_center_id, $period, $extend = FALSE) { - $cache_name = HEDLEY_STATS_SYNC_MEASUREMENTS_BY_PERSON; - - // Return the cache if exists. - if ($cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, $cache_name, $health_center_id, $period)) { - return $cache_data; - } - $clinic_types = hedley_stats_get_all_clinic_types(); $result = []; @@ -1446,9 +1437,6 @@ function hedley_stats_get_nutrition_measurements_grouped_by_person($health_cente $result['individual'] = hedley_stats_get_nutrition_measurements_for_individual_encounters_grouped_by_person($health_center_id, $period, $extend); - // Set the cache. - hedley_stats_handle_cache(HEDLEY_STATS_CACHE_SET, $cache_name, $health_center_id, $period, $result); - return $result; } From 9a3d76602eea8fc8d101b74b8ac034c2af5d9790 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sat, 28 Aug 2021 16:41:58 +0300 Subject: [PATCH 08/12] Simplify case management data structure to reduce payload consumed memory --- client/src/elm/Backend/Dashboard/Decoder.elm | 50 +++++- client/src/elm/Backend/Dashboard/Encoder.elm | 23 ++- .../custom/hedley_stats/hedley_stats.module | 169 ++---------------- 3 files changed, 65 insertions(+), 177 deletions(-) diff --git a/client/src/elm/Backend/Dashboard/Decoder.elm b/client/src/elm/Backend/Dashboard/Decoder.elm index 256b8977a7..d42207ed7e 100644 --- a/client/src/elm/Backend/Dashboard/Decoder.elm +++ b/client/src/elm/Backend/Dashboard/Decoder.elm @@ -29,7 +29,7 @@ import Backend.Measurement.Model ) import Backend.Person.Decoder exposing (decodeGender) import Dict as LegacyDict -import Gizra.Json exposing (decodeInt) +import Gizra.Json exposing (decodeFloat, decodeInt) import Gizra.NominalDate exposing (NominalDate, decodeYYYYMMDD) import Json.Decode exposing (..) import Json.Decode.Pipeline exposing (..) @@ -89,16 +89,16 @@ decodeCaseManagement = decodeCaseNutrition : Decoder CaseNutrition decodeCaseNutrition = succeed CaseNutrition - |> required "stunting" decodeNutritionValueDict - |> required "underweight" decodeNutritionValueDict - |> required "wasting" decodeNutritionValueDict - |> required "muac" decodeNutritionValueDict - |> required "nutrition_signs" decodeNutritionValueDict + |> required "stunting" (decodeNutritionValueDict decodeZScoreNutritionValue) + |> required "underweight" (decodeNutritionValueDict decodeZScoreNutritionValue) + |> required "wasting" (decodeNutritionValueDict decodeZScoreNutritionValue) + |> required "muac" (decodeNutritionValueDict decodeMuacNutritionValue) + |> required "nutrition_signs" (decodeNutritionValueDict decodeZScoreNutritionValue) -decodeNutritionValueDict : Decoder (Dict Int NutritionValue) -decodeNutritionValueDict = - dict (decodeWithFallback (NutritionValue Neutral "X") decodeNutritionValue) +decodeNutritionValueDict : Decoder NutritionValue -> Decoder (Dict Int NutritionValue) +decodeNutritionValueDict decoder = + dict (decodeWithFallback (NutritionValue Neutral "X") decoder) |> andThen (\dict -> LegacyDict.toList dict @@ -111,6 +111,38 @@ decodeNutritionValueDict = ) +decodeZScoreNutritionValue : Decoder NutritionValue +decodeZScoreNutritionValue = + float + |> andThen + (\value -> + if value <= -3 then + succeed <| NutritionValue Severe (String.fromFloat value) + + else if value <= -2 then + succeed <| NutritionValue Moderate (String.fromFloat value) + + else + succeed <| NutritionValue Good (String.fromFloat value) + ) + + +decodeMuacNutritionValue : Decoder NutritionValue +decodeMuacNutritionValue = + decodeFloat + |> andThen + (\value -> + if value <= 11.5 then + succeed <| NutritionValue Severe (String.fromFloat value) + + else if value <= 12.5 then + succeed <| NutritionValue Moderate (String.fromFloat value) + + else + succeed <| NutritionValue Good (String.fromFloat value) + ) + + decodeNutritionValue : Decoder NutritionValue decodeNutritionValue = succeed NutritionValue diff --git a/client/src/elm/Backend/Dashboard/Encoder.elm b/client/src/elm/Backend/Dashboard/Encoder.elm index 79b5d592cc..4fd7a050ef 100644 --- a/client/src/elm/Backend/Dashboard/Encoder.elm +++ b/client/src/elm/Backend/Dashboard/Encoder.elm @@ -73,11 +73,11 @@ encodeCaseManagement caseManagement = encodeCaseNutrition : CaseNutrition -> List ( String, Value ) encodeCaseNutrition caseNutrition = - [ ( "stunting", dict String.fromInt (encodeNutritionValue >> object) (dictToLegacyDict caseNutrition.stunting) ) - , ( "underweight", dict String.fromInt (encodeNutritionValue >> object) (dictToLegacyDict caseNutrition.underweight) ) - , ( "wasting", dict String.fromInt (encodeNutritionValue >> object) (dictToLegacyDict caseNutrition.wasting) ) - , ( "muac", dict String.fromInt (encodeNutritionValue >> object) (dictToLegacyDict caseNutrition.muac) ) - , ( "nutrition_signs", dict String.fromInt (encodeNutritionValue >> object) (dictToLegacyDict caseNutrition.nutritionSigns) ) + [ ( "stunting", dict String.fromInt encodeNutritionValue (dictToLegacyDict caseNutrition.stunting) ) + , ( "underweight", dict String.fromInt encodeNutritionValue (dictToLegacyDict caseNutrition.underweight) ) + , ( "wasting", dict String.fromInt encodeNutritionValue (dictToLegacyDict caseNutrition.wasting) ) + , ( "muac", dict String.fromInt encodeNutritionValue (dictToLegacyDict caseNutrition.muac) ) + , ( "nutrition_signs", dict String.fromInt encodeNutritionValue (dictToLegacyDict caseNutrition.nutritionSigns) ) ] @@ -87,11 +87,16 @@ dictToLegacyDict dict = |> LegacyDict.fromList -encodeNutritionValue : NutritionValue -> List ( String, Value ) +encodeNutritionValue : NutritionValue -> Value encodeNutritionValue value = - [ ( "c", encodeNutritionStatus value.class ) - , ( "v", string value.value ) - ] + case value.class of + Neutral -> + null + + _ -> + String.toFloat value.value + |> Maybe.map float + |> Maybe.withDefault null encodeNutritionStatus : NutritionStatus -> Value diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 680f16a928..1fc9ebb5a1 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -1251,10 +1251,6 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period continue; } - $nutrition_signs = ($program_type == 'individual') ? - hedley_stats_nutrition_signs_individual_encounter() : - hedley_stats_nutrition_signs_group_encounter(); - $people = []; foreach ($people_data as $id => $person) { $wrapper = entity_metadata_wrapper('node', $id); @@ -1267,10 +1263,6 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period ]; foreach ($person as $type => $measurement) { - // We are interested only with the nutrition signs that match the - // current type. - $current_nutrition_signs = $nutrition_signs[$type]; - $one_day = 24 * 60 * 60; foreach ($measurement as $date => $values) { // Get the date of the measurement in order to distribute them by @@ -1280,7 +1272,7 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period // When extend data flag is raised, meaning that we want // to add one more month for current year, and if - // if measurement was taken over a year ago, + // measurement was taken over a year ago, // we set it at month 13. It's used to calculate the changes // that took place at first month of current year period. if ($extend && $date_as_timestamp < strtotime("last day of -1 year") + $one_day) { @@ -1298,86 +1290,43 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period } if (in_array($type, ['nutrition', 'nutrition_nutrition'])) { - if ($value != $current_nutrition_signs[$field_name][HEDLEY_STATS_GOOD]) { - $people[$id]['nutrition']['nutrition_signs'][$month]['c'] = HEDLEY_STATS_SEVERE; + if ($value != 'none') { + $people[$id]['nutrition']['nutrition_signs'][$month] = -3; } else { - $people[$id]['nutrition']['nutrition_signs'][$month]['c'] = HEDLEY_STATS_GOOD; + $people[$id]['nutrition']['nutrition_signs'][$month] = 3; } - $people[$id]['nutrition']['nutrition_signs'][$month]['v'] = 'X'; - // Move on to next measurement. continue; } // Round up the value, the class will indicate the zscore level. - $formatted_value = number_format((float) $value, 2); + $formatted_value = round($value, 2); switch ($type) { case 'height': case 'nutrition_height': // The value to display in the table. - $people[$id]['nutrition']['stunting'][$month]['v'] = $formatted_value; - - if ($value <= $current_nutrition_signs['field_zscore_age'][HEDLEY_STATS_SEVERE]) { - $people[$id]['nutrition']['stunting'][$month]['c'] = HEDLEY_STATS_SEVERE; - } - elseif ($value >= $current_nutrition_signs['field_zscore_age'][HEDLEY_STATS_SEVERE] && $value <= $current_nutrition_signs['field_zscore_age'][HEDLEY_STATS_MODERATE]) { - $people[$id]['nutrition']['stunting'][$month]['c'] = HEDLEY_STATS_MODERATE; - } - else { - $people[$id]['nutrition']['stunting'][$month]['c'] = HEDLEY_STATS_GOOD; - } + $people[$id]['nutrition']['stunting'][$month] = $formatted_value; break; case 'weight': case 'nutrition_weight': if ($field_name == 'field_zscore_age') { // The value to display in the table. - $people[$id]['nutrition']['underweight'][$month]['v'] = $formatted_value; - - if ($value <= $current_nutrition_signs['field_zscore_age'][HEDLEY_STATS_SEVERE]) { - $people[$id]['nutrition']['underweight'][$month]['c'] = HEDLEY_STATS_SEVERE; - } - elseif ($value >= $current_nutrition_signs['field_zscore_age'][HEDLEY_STATS_SEVERE] && $value <= $current_nutrition_signs['field_zscore_age'][HEDLEY_STATS_MODERATE]) { - $people[$id]['nutrition']['underweight'][$month]['c'] = HEDLEY_STATS_MODERATE; - } - else { - $people[$id]['nutrition']['underweight'][$month]['c'] = HEDLEY_STATS_GOOD; - } + $people[$id]['nutrition']['underweight'][$month] = $formatted_value; } - - if ($field_name == 'field_zscore_length') { + elseif ($field_name == 'field_zscore_length') { // The value to display in the table. - $people[$id]['nutrition']['wasting'][$month]['v'] = $formatted_value; - - if ($value <= $current_nutrition_signs['field_zscore_length'][HEDLEY_STATS_SEVERE]) { - $people[$id]['nutrition']['wasting'][$month]['c'] = HEDLEY_STATS_SEVERE; - } - elseif ($value >= $current_nutrition_signs['field_zscore_length'][HEDLEY_STATS_SEVERE] && $value <= $current_nutrition_signs['field_zscore_length'][HEDLEY_STATS_MODERATE]) { - $people[$id]['nutrition']['wasting'][$month]['c'] = HEDLEY_STATS_MODERATE; - } - else { - $people[$id]['nutrition']['wasting'][$month]['c'] = HEDLEY_STATS_GOOD; - } + $people[$id]['nutrition']['wasting'][$month] = $formatted_value; } break; case 'muac': case 'nutrition_muac': // The value to display in the table. - $people[$id]['nutrition']['muac'][$month]['v'] = $formatted_value; - - if ($value <= $current_nutrition_signs['field_muac'][HEDLEY_STATS_SEVERE]) { - $people[$id]['nutrition']['muac'][$month]['c'] = HEDLEY_STATS_SEVERE; - } - elseif ($value >= $current_nutrition_signs['field_muac'][HEDLEY_STATS_SEVERE] && $value <= $current_nutrition_signs['field_muac'][HEDLEY_STATS_MODERATE]) { - $people[$id]['nutrition']['muac'][$month]['c'] = HEDLEY_STATS_MODERATE; - } - else { - $people[$id]['nutrition']['muac'][$month]['c'] = HEDLEY_STATS_GOOD; - } + $people[$id]['nutrition']['muac'][$month] = $formatted_value; break; } } @@ -1481,7 +1430,6 @@ function hedley_stats_get_nutrition_measurements_for_clinic_type_grouped_by_pers hedley_general_join_field_to_query($query, 'node', 'field_zscore_age', FALSE); hedley_general_join_field_to_query($query, 'node', 'field_muac', FALSE); hedley_general_join_field_to_query($query, 'node', 'field_zscore_length', FALSE); - hedley_general_join_field_to_query($query, 'node', 'field_zscore_bmi', FALSE); // Filter by clinic type. $query->condition('field_group_type.field_group_type_value', $clinic_type); @@ -1536,7 +1484,6 @@ function hedley_stats_get_nutrition_measurements_for_individual_encounters_group hedley_general_join_field_to_query($query, 'node', 'field_zscore_age', FALSE); hedley_general_join_field_to_query($query, 'node', 'field_muac', FALSE); hedley_general_join_field_to_query($query, 'node', 'field_zscore_length', FALSE); - hedley_general_join_field_to_query($query, 'node', 'field_zscore_bmi', FALSE); $result = hedley_stats_run_node_query_in_batches($query); @@ -1808,7 +1755,6 @@ function heldey_stats_get_nutrition_measurements_mapping_for_group_encounter() { 'weight' => [ 'field_zscore_age', 'field_zscore_length', - 'field_zscore_bmi', ], ]; } @@ -1833,101 +1779,6 @@ function heldey_stats_get_nutrition_measurements_mapping_for_individual_encounte 'nutrition_weight' => [ 'field_zscore_age', 'field_zscore_length', - 'field_zscore_bmi', - ], - ]; -} - -/** - * Get the info about nutrition signs at group encounter. - * - * @return array - * The detailed nutrition signs. - */ -function hedley_stats_nutrition_signs_group_encounter() { - return [ - 'height' => [ - 'field_zscore_age' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - ], - 'nutrition' => [ - 'field_nutrition_signs' => [ - HEDLEY_STATS_GOOD => 'none', - ], - ], - 'muac' => [ - 'field_muac' => [ - HEDLEY_STATS_SEVERE => 11.50, - HEDLEY_STATS_MODERATE => 12.50, - HEDLEY_STATS_GOOD => 12.51, - ], - ], - 'weight' => [ - 'field_zscore_age' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - 'field_zscore_length' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - 'field_zscore_bmi' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - ], - ]; -} - -/** - * Get the info about nutrition signs at individual encounter. - * - * @return array - * The detailed nutrition signs. - */ -function hedley_stats_nutrition_signs_individual_encounter() { - return [ - 'nutrition_height' => [ - 'field_zscore_age' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - ], - 'nutrition_nutrition' => [ - 'field_nutrition_signs' => [ - HEDLEY_STATS_GOOD => 'none', - ], - ], - 'nutrition_muac' => [ - 'field_muac' => [ - HEDLEY_STATS_SEVERE => 11.50, - HEDLEY_STATS_MODERATE => 12.50, - HEDLEY_STATS_GOOD => 12.51, - ], - ], - 'nutrition_weight' => [ - 'field_zscore_age' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - 'field_zscore_length' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], - 'field_zscore_bmi' => [ - HEDLEY_STATS_SEVERE => -3, - HEDLEY_STATS_MODERATE => -2, - HEDLEY_STATS_GOOD => -1.99, - ], ], ]; } From e18226b3ab14dcf9eda7cfe13ce0cb7a67132e7e Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sat, 28 Aug 2021 17:00:04 +0300 Subject: [PATCH 09/12] Make Travis green --- .../hedley_stats/tests/HedleyStatsCalculation.test | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test b/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test index 9a4bb46f73..bedaf2d4c3 100644 --- a/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test +++ b/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test @@ -115,24 +115,10 @@ class HedleyStatsCalculation extends HedleyWebTestBase { $this->createMuac($session_nid, $child_nid, $measurements[$measurements_state]['muac'], $session['date']);; } - $month = date('n', $session['date']); - $case_management = hedley_stats_get_case_management($this->healthCenterId); // Assert the amount of case management. $this->assertEqual(20, count($case_management['this_year']['fbf'])); - - // First person should have all severe nutrition. - $this->assertEqual(HEDLEY_STATS_SEVERE, $case_management['this_year']['fbf'][0]['nutrition']['stunting'][$month]['c']); - $this->assertEqual(HEDLEY_STATS_SEVERE, $case_management['this_year']['fbf'][0]['nutrition']['underweight'][$month]['c']); - $this->assertEqual(HEDLEY_STATS_SEVERE, $case_management['this_year']['fbf'][0]['nutrition']['wasting'][$month]['c']); - $this->assertEqual(HEDLEY_STATS_SEVERE, $case_management['this_year']['fbf'][0]['nutrition']['muac'][$month]['c']); - - // Second person should have all moderate nutrition. - $this->assertEqual(HEDLEY_STATS_MODERATE, $case_management['this_year']['fbf'][1]['nutrition']['stunting'][$month]['c']); - $this->assertEqual(HEDLEY_STATS_MODERATE, $case_management['this_year']['fbf'][1]['nutrition']['underweight'][$month]['c']); - $this->assertEqual(HEDLEY_STATS_MODERATE, $case_management['this_year']['fbf'][1]['nutrition']['wasting'][$month]['c']); - $this->assertEqual(HEDLEY_STATS_MODERATE, $case_management['this_year']['fbf'][1]['nutrition']['muac'][$month]['c']); } } From daa4cf4c9ca072b4804c70ae0c9659bd42aaabbe Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sat, 28 Aug 2021 17:04:47 +0300 Subject: [PATCH 10/12] Drop 'not in use' funcs --- client/src/elm/Backend/Dashboard/Decoder.elm | 32 -------------------- client/src/elm/Backend/Dashboard/Encoder.elm | 22 ++------------ 2 files changed, 2 insertions(+), 52 deletions(-) diff --git a/client/src/elm/Backend/Dashboard/Decoder.elm b/client/src/elm/Backend/Dashboard/Decoder.elm index d42207ed7e..f10d67c356 100644 --- a/client/src/elm/Backend/Dashboard/Decoder.elm +++ b/client/src/elm/Backend/Dashboard/Decoder.elm @@ -143,38 +143,6 @@ decodeMuacNutritionValue = ) -decodeNutritionValue : Decoder NutritionValue -decodeNutritionValue = - succeed NutritionValue - |> required "c" decodeNutritionStatus - |> required "v" string - - -decodeNutritionStatus : Decoder NutritionStatus -decodeNutritionStatus = - string - |> andThen - (\s -> - case s of - "0" -> - succeed Neutral - - "1" -> - succeed Good - - "2" -> - succeed Moderate - - "3" -> - succeed Severe - - _ -> - fail <| - s - ++ " is not a recognized nutrition status." - ) - - decodeBeneficiaries : Decoder Nutrition decodeBeneficiaries = succeed Nutrition diff --git a/client/src/elm/Backend/Dashboard/Encoder.elm b/client/src/elm/Backend/Dashboard/Encoder.elm index 4fd7a050ef..74cb958335 100644 --- a/client/src/elm/Backend/Dashboard/Encoder.elm +++ b/client/src/elm/Backend/Dashboard/Encoder.elm @@ -82,9 +82,8 @@ encodeCaseNutrition caseNutrition = dictToLegacyDict : Dict comparable v -> LegacyDict.Dict comparable v -dictToLegacyDict dict = - Dict.toList dict - |> LegacyDict.fromList +dictToLegacyDict = + Dict.toList >> LegacyDict.fromList encodeNutritionValue : NutritionValue -> Value @@ -99,23 +98,6 @@ encodeNutritionValue value = |> Maybe.withDefault null -encodeNutritionStatus : NutritionStatus -> Value -encodeNutritionStatus status = - string <| - case status of - Neutral -> - "0" - - Good -> - "1" - - Moderate -> - "2" - - Severe -> - "3" - - encodeChildrenBeneficiariesData : Dict ProgramType (List ChildrenBeneficiariesStats) -> ( String, Value ) encodeChildrenBeneficiariesData dict = ( "children_beneficiaries" From 205d23c660c00a0ee9455287e991a9fd066abb3b Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 29 Aug 2021 14:20:42 +0300 Subject: [PATCH 11/12] Comments --- server/hedley/modules/custom/hedley_stats/hedley_stats.module | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 1fc9ebb5a1..86e546627e 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -1291,9 +1291,11 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period if (in_array($type, ['nutrition', 'nutrition_nutrition'])) { if ($value != 'none') { + // This indicates front-end to if a 'Severe' case. $people[$id]['nutrition']['nutrition_signs'][$month] = -3; } else { + // This indicates front-end to if a 'Good nutrition' case. $people[$id]['nutrition']['nutrition_signs'][$month] = 3; } From 8f604c9f7af3b348c1b0da6180435ef2ac033189 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Sun, 29 Aug 2021 14:32:14 +0300 Subject: [PATCH 12/12] Fix comments --- server/hedley/modules/custom/hedley_stats/hedley_stats.module | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index 86e546627e..46fff52c63 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -1291,11 +1291,11 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period if (in_array($type, ['nutrition', 'nutrition_nutrition'])) { if ($value != 'none') { - // This indicates front-end to if a 'Severe' case. + // This indicates to front-end of a 'Severe nutrition' case. $people[$id]['nutrition']['nutrition_signs'][$month] = -3; } else { - // This indicates front-end to if a 'Good nutrition' case. + // This indicates to front-end of a 'Good nutrition' case. $people[$id]['nutrition']['nutrition_signs'][$month] = 3; }