feat: add parent survey gauges

mciea-main
Nelson Jovel 1 year ago
parent 695f8b69a2
commit c85ddddd8d

@ -1 +1 @@
3.3.4
3.3.5

@ -24,6 +24,10 @@ class Measure < ActiveRecord::Base
@student_survey_items ||= survey_items.student_survey_items
end
def parent_survey_items
@parent_survey_items ||= survey_items.parent_survey_items
end
def student_survey_items_with_sufficient_responses(school:, academic_year:)
@student_survey_items_with_sufficient_responses ||= Hash.new do |memo, (school, academic_year)|
memo[[school, academic_year]] = SurveyItem.where(id: SurveyItem.joins("inner join survey_item_responses on survey_item_responses.survey_item_id = survey_items.id")
@ -59,6 +63,10 @@ class Measure < ActiveRecord::Base
@includes_admin_data_items ||= admin_data_items.length.positive?
end
def includes_parent_survey_items?
@includes_parent_survey_items ||= parent_survey_items.length.positive?
end
def score(school:, academic_year:)
@score ||= Hash.new do |memo, (school, academic_year)|
next Score::NIL_SCORE if incalculable_score(school:, academic_year:)
@ -103,6 +111,15 @@ class Measure < ActiveRecord::Base
@admin_score[[school, academic_year]]
end
def parent_score(school:, academic_year:)
@parent_score ||= Hash.new do |memo, (school, academic_year)|
average = parent_averages(school:, academic_year:).average.round(2)
memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
end
@parent_score[[school, academic_year]]
end
def warning_low_benchmark
1
end
@ -222,4 +239,9 @@ class Measure < ActiveRecord::Base
def admin_data_averages(school:, academic_year:)
AdminDataValue.where(school:, academic_year:, admin_data_item: admin_data_items).pluck(:likert_score)
end
def parent_averages(school:, academic_year:)
SurveyItemResponse.where(school:, academic_year:,
survey_item_id: parent_survey_items).group(:survey_item).average(:likert_score).values
end
end

@ -30,6 +30,9 @@ class SurveyItem < ActiveRecord::Base
scope :early_education_survey_items, lambda {
where("survey_items.survey_item_id LIKE '%-%-es%'")
}
scope :parent_survey_items, lambda {
where("survey_items.survey_item_id LIKE 'p-%'")
}
scope :survey_items_for_grade, lambda { |school, academic_year, grade|
includes(:survey_item_responses)
@ -76,6 +79,8 @@ class SurveyItem < ActiveRecord::Base
return :teacher if survey_item_ids.subset? teacher_survey_items.map(&:survey_item_id).to_set
return :standard if survey_item_ids.subset? standard_survey_items.map(&:survey_item_id).to_set
return :parent if parent_survey_items.count.positive?
:unknown
end
end

@ -0,0 +1,24 @@
# frozen_string_literal: true
class ParentMeasurePresenter < MeasurePresenter
def measure_id
"#{measure.measure_id} (Parent)"
end
def score_for_measure
@measure.parent_score(school: @school, academic_year: @academic_year)
end
def data_item_presenters
[].tap do |array|
array << parent_survey_presenter if measure.parent_survey_items.any?
end
end
private
def parent_survey_presenter
ParentSurveyPresenter.new(measure_id: measure.measure_id, survey_items: measure.parent_survey_items,
has_sufficient_data: true, school:, academic_year:)
end
end

@ -0,0 +1,26 @@
# frozen_string_literal: true
class ParentSurveyPresenter < DataItemPresenter
attr_reader :survey_items
def initialize(measure_id:, survey_items:, has_sufficient_data:, school:, academic_year:)
super(measure_id:, has_sufficient_data:, school:, academic_year:)
@survey_items = survey_items
end
def title
"Parent survey"
end
def id
"parent-survey-items-#{measure_id}"
end
def reason_for_insufficiency
"low response rate"
end
def descriptions_and_availability
survey_items.map(&:description)
end
end

@ -43,12 +43,22 @@ class SubcategoryPresenter
def measure_presenters
@subcategory.measures.sort_by(&:measure_id).map do |measure|
MeasurePresenter.new(measure:, academic_year: @academic_year, school: @school)
end
out = [MeasurePresenter.new(measure:, academic_year: @academic_year, school: @school)]
if parent_gauges_have_displayable_score?(measure:)
out << ParentMeasurePresenter.new(measure:, academic_year: @academic_year,
school: @school)
end
out
end.flatten
end
private
def parent_gauges_have_displayable_score?(measure:)
measure.includes_parent_survey_items? && measure.parent_score(school: @school,
academic_year: @academic_year).average.positive?
end
def admin_data_values_count
@subcategory.measures.map do |measure|
measure.scales.map do |scale|

@ -27,7 +27,7 @@ class Cleaner
def filename(headers:, data:, filepath:)
output = []
survey_item_ids = headers.filter(&:present?).filter do |header|
header.start_with?("s-", "t-")
header.start_with?("s-", "t-", "p-")
end.reject { |item| item.end_with? "-1" }
survey_type = SurveyItem.survey_type(survey_item_ids:)
range = data.first.academic_year.range
@ -129,7 +129,7 @@ class Cleaner
def remove_unwanted_headers(headers:)
headers.to_set.to_a.compact.reject do |item|
item.start_with? "Q"
end.reject { |header| header.match?(/^[st]-\w*-\w*-1$/i) }
end.reject { |header| header.match?(/^[stp]-\w*-\w*-1$/i) }
end
def write_csv(data:, output_filepath:, filename:, prefix: "")
@ -152,7 +152,7 @@ class Cleaner
def survey_items(headers:)
survey_item_ids = headers
.filter(&:present?)
.filter { |header| header.start_with? "t-", "s-" }
.filter { |header| header.start_with? "t-", "s-", "p-" }
@survey_items ||= SurveyItem.where(survey_item_id: survey_item_ids)
end

@ -208,7 +208,7 @@ class SurveyItemValues
def sanitized_headers
@sanitized_headers ||= headers.select(&:present?)
.reject { |key, _value| key.start_with? "Q" }
.reject { |key, _value| key.match?(/^[st]-\w*-\w*-1$/i) }
.reject { |key, _value| key.match?(/^[stp]-\w*-\w*-1$/i) }
end
def to_a
@ -228,6 +228,10 @@ class SurveyItemValues
.filter(&:present?)
.filter { |header| header.start_with? "t-" }.count > 0
return :parent if headers
.filter(&:present?)
.filter { |header| header.start_with? "p-" }.count > 0
:student
end
@ -236,7 +240,7 @@ class SurveyItemValues
end
def survey_item_ids
@survey_item_ids ||= sanitized_headers.filter { |header| header.start_with?("t-", "s-") }
@survey_item_ids ||= sanitized_headers.filter { |header| header.start_with?("t-", "s-", "p-") }
end
def valid_duration?
@ -246,6 +250,7 @@ class SurveyItemValues
return span_in_seconds >= 300 if survey_type == :teacher
return span_in_seconds >= 240 if survey_type == :standard
return span_in_seconds >= 100 if survey_type == :short_form
return span_in_seconds >= 120 if survey_type == :parent
true
end
@ -261,6 +266,7 @@ class SurveyItemValues
return progress >= 11 if survey_type == :standard
return progress >= 5 if survey_type == :short_form
return progress >= 5 if survey_type == :early_education
return true if survey_type == :parent
false
end
@ -269,6 +275,7 @@ class SurveyItemValues
return true if grade.nil?
return true if respondent_type == :teacher
return true if survey_type == :parent
respondents = Respondent.where(school:, academic_year:).first
if respondents.present? && respondents.enrollment_by_grade[grade].present?
@ -283,6 +290,7 @@ class SurveyItemValues
def valid_sd?
return true if survey_type == :early_education
return true if survey_type == :parent
survey_item_headers = headers.filter(&:present?).filter { |header| header.start_with?("s-", "t-") }
likert_scores = []

@ -161,7 +161,7 @@ class SurveyResponsesDataLoader
.parse(headers)
.first
.filter(&:present?)
.filter { |header| header.start_with?("t-", "s-") }
.filter { |header| header.start_with?("t-", "s-", "p-") }
end
end

File diff suppressed because one or more lines are too long

@ -36,6 +36,10 @@ RSpec.describe Cleaner do
File.open(Rails.root.join("spec", "fixtures", "raw", "sample_file_with_duplicate_headers.csv"))
end
let(:path_to_sample_raw_parent_file) do
File.open(Rails.root.join("spec", "fixtures", "raw", "sample_maynard_raw_parent_survey.csv"))
end
let(:common_headers) do
["Recorded Date", "Dese ID", "ResponseID"]
end
@ -82,6 +86,51 @@ RSpec.describe Cleaner do
survey_item_ids
end
let(:parent_survey_items) do
survey_item_ids = (%w[
p-socx-q1
p-socx-q2
p-socx-q3
p-socx-q4
p-sosu-q1
p-sosu-q2
p-sosu-q3
p-sosu-q4
p-tcom-q1
p-tcom-q2
p-tcom-q3
p-comm-q1
p-comm-q2
p-comm-q3
p-comm-q4
p-valm-q1
p-valm-q2
p-valm-q3
p-valm-q4
p-acpr-q1
p-acpr-q2
p-acpr-q3
p-acpr-q4
p-scrp-q3
p-cure-q1
p-cure-q2
p-cure-q3
p-cure-q4
p-evnt-q1
p-evnt-q2
p-evnt-q3
p-evnt-q4
p-phys-q3
p-scrp-q1
p-scrp-q2
] << common_headers).flatten
survey_item_ids.map do |survey_item_id|
create(:survey_item, survey_item_id:)
end
survey_item_ids
end
before :each do
school
second_school
@ -198,6 +247,19 @@ RSpec.describe Cleaner do
end
end
context "when the file is based on parent survey items" do
it "adds the survey type as parent to the filename" do
survey_items = SurveyItem.where(survey_item_id: parent_survey_items)
data = [SurveyItemValues.new(row: { "Recorded Date" => recorded_date, "Dese ID" => "1_740_505" }, headers: parent_survey_items, survey_items:,
schools: School.by_dese_id)]
filename = Cleaner.new(input_filepath:, output_filepath:, log_filepath:).filename(
headers: parent_survey_items, data:, filepath: nil
)
expect(filename).to eq "maynard.maynard-high-school.parent.2022-23.csv"
end
end
context "when there is more than one district" do
it "adds all districts to the filename" do
survey_items = SurveyItem.where(survey_item_id: teacher_survey_items)

Loading…
Cancel
Save