From d82f40aa3d99ea18ce13351d5ee9a5e9a5d89092 Mon Sep 17 00:00:00 2001 From: Gabe Farrell Date: Mon, 15 Apr 2024 16:17:13 -0400 Subject: [PATCH] Feat: add grade-level survey item report --- app/models/report/survey_item.rb | 83 +++++++++++++++++++++++++++++++- lib/tasks/report.rake | 5 +- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/app/models/report/survey_item.rb b/app/models/report/survey_item.rb index db34ed7c..93f5ce5e 100644 --- a/app/models/report/survey_item.rb +++ b/app/models/report/survey_item.rb @@ -1,6 +1,85 @@ module Report class SurveyItem - def self.create_report(school:, academic_year:, filename:) + def self.create_grade_report(school:, academic_year:) + # get list of survey items with sufficient responses + survey_items = Set.new + # also get a map of grade->survey_id + sufficient_survey_items = Hash.new + school.grades(academic_year:).each do |grade| + sufficient_survey_items[grade] ||= Set.new + end + SurveyItemResponse.student_survey_items_with_responses_by_grade( + school:, + academic_year:, + ).each do |key,count| + # key[1] is survey item id + survey_items.add(key[1]) + sufficient_survey_items[key[0]].add(key[1]) if count >= 10 + end + # write headers + headers = [ + "School Name", + "Grade", + ] + survey_items.each do |survey_item_id| + headers << ::SurveyItem.find_by_id(survey_item_id).prompt + end + data = [] + data << headers + # for each grade, iterate through all survey items in our list + # if it has sufficient responses, write out the avg score + # else, write 'N/A' + school.grades(academic_year:).sort.each do |grade| + next if grade == -1 # skip pre-k + row = [] + row << school.name + if grade == 0 + row.append("Kindergarten") + else + row.append("Grade #{grade}") + end + survey_items.each do |survey_item_id| + survey_item = ::SurveyItem.find_by_id survey_item_id + if sufficient_survey_items[grade].include? survey_item_id + row.append("#{survey_item.survey_item_responses.where(school:, academic_year:, grade:).average(:likert_score).to_f.round(2)}") + else + row.append("N/A") + end + end + data << row + end + + # now iterate through all survey items again + # if the whole school has sufficient responses, write the school avg + # else, N/A + row = [] + row.append(school.name) + row.append("All School") + survey_items.each do |survey_item_id| + survey_item = ::SurveyItem.find_by_id survey_item_id +# filter out response rate at subcategory level <24.5% for school average + scale = Scale.find_by_id(survey_item.scale_id) + measure = ::Measure.find_by_id(scale.measure_id) + subcategory = ::Subcategory.find_by_id(measure.subcategory_id) + if ::StudentResponseRateCalculator.new(subcategory:, school:, academic_year:).meets_student_threshold? + row.append("#{survey_item.survey_item_responses.where( + # We allow the nil (unknown) grades in the school survey item average + # also filter less than 10 responses in the whole school + "school_id = ? and academic_year_id = ? and (grade IS NULL or grade IN (?))", school.id, academic_year.id, school.grades(academic_year:) + ).group("survey_item_id").having("count(*) >= 10").average(:likert_score).values[0].to_f.round(2)}") + else + row.append("N/A") + end + end + data << row + # write out file + FileUtils.mkdir_p Rails.root.join("tmp", "reports") + filepath = Rails.root.join("tmp", "reports", "survey_item_report_by_grade.csv") + write_csv(data:, filepath:) + data + end + + def self.create_item_report(school:, academic_year:) # first, determine headers by finding the school and grades # Q: Should a grade not be included if it has no sufficient responses? # A: Include all grades, except preschool @@ -84,7 +163,7 @@ module Report data << row end FileUtils.mkdir_p Rails.root.join("tmp", "reports") - filepath = Rails.root.join("tmp", "reports", filename) + filepath = Rails.root.join("tmp", "reports", "survey_item_report_by_item.csv") write_csv(data:, filepath:) data end diff --git a/lib/tasks/report.rake b/lib/tasks/report.rake index 64dfcba6..070d349e 100644 --- a/lib/tasks/report.rake +++ b/lib/tasks/report.rake @@ -72,7 +72,7 @@ namespace :report do end namespace :survey_item do - task :by_item, [:school, :academic_year] => :environment do |_, args| + task :create, [:school, :academic_year] => :environment do |_, args| school = School.find_by_name(args[:school]) academic_year = AcademicYear.find_by_range(args[:academic_year]) if school == nil @@ -84,7 +84,8 @@ namespace :report do bad = 1 end next if bad == 1 - Report::SurveyItem.create_report(school: , academic_year:, filename: "survey_item_by_item_report.csv") + Report::SurveyItem.create_item_report(school:, academic_year:) + Report::SurveyItem.create_grade_report(school:, academic_year:) end end end