# frozen_string_literal: true class StudentResponseRateCalculator < ResponseRateCalculator def raw_response_rate rates_by_grade.values.length.positive? ? weighted_average : 0 end def weighted_average num_possible_responses = 0.0 rates_by_grade.keys.map do |grade| num_possible_responses += enrollment_by_grade[grade] end rates_by_grade.map do |grade, rate| rate * (enrollment_by_grade[grade] / num_possible_responses) end.sum end def rates_by_grade @rates_by_grade ||= enrollment_by_grade.map do |grade, num_of_students_in_grade| responses = survey_items_with_sufficient_responses(grade:) actual_response_count_for_grade = responses.values.sum.to_f count_of_survey_items_with_sufficient_responses = responses.count if actual_response_count_for_grade.nil? || count_of_survey_items_with_sufficient_responses.nil? || count_of_survey_items_with_sufficient_responses.zero? || num_of_students_in_grade.nil? || num_of_students_in_grade.zero? next nil end rate = actual_response_count_for_grade / count_of_survey_items_with_sufficient_responses / num_of_students_in_grade * 100 [grade, rate] end.compact.to_h end def enrollment_by_grade @enrollment_by_grade ||= respondents.enrollment_by_grade end def survey_items_have_sufficient_responses? rates_by_grade.values.length.positive? end def survey_items_with_sufficient_responses(grade:) @survey_items_with_sufficient_responses ||= Hash.new do |memo, grade| threshold = 10 quarter_of_grade = enrollment_by_grade[grade] / 4 threshold = threshold > quarter_of_grade ? quarter_of_grade : threshold memo[grade] = SurveyItem.joins("inner join survey_item_responses on survey_item_responses.survey_item_id = survey_items.id") .student_survey_items .where("survey_item_responses.school": school, "survey_item_responses.academic_year": academic_year, "survey_item_responses.grade": grade, "survey_item_responses.survey_item_id": subcategory.survey_items.student_survey_items) .group("survey_items.id") .having("count(*) >= #{threshold}") .count end @survey_items_with_sufficient_responses[grade] end def total_possible_responses @total_possible_responses ||= begin return 0 unless respondents.present? respondents.total_students end end end