diff --git a/app/models/attempt.rb b/app/models/attempt.rb index 5ddf65a9..7f80d578 100644 --- a/app/models/attempt.rb +++ b/app/models/attempt.rb @@ -6,11 +6,14 @@ class Attempt < ApplicationRecord belongs_to :recipient belongs_to :recipient_schedule belongs_to :question + belongs_to :student after_save :update_school_categories after_commit :update_counts scope :for_question, -> (question) { where(question_id: question.id) } + scope :for_recipient, -> (recipient) { where(recipient_id: recipient.id) } + scope :for_student, -> (student) { where(student_id: student.id) } scope :for_category, -> (category) { joins(:question).merge(Question.for_category(category)) } scope :for_school, -> (school) { joins(:recipient).merge(Recipient.for_school(school)) } scope :with_response, -> { where('answer_index is not null or open_response_id is not null')} diff --git a/app/models/recipient_schedule.rb b/app/models/recipient_schedule.rb index 55b6a313..bd95f014 100644 --- a/app/models/recipient_schedule.rb +++ b/app/models/recipient_schedule.rb @@ -31,30 +31,71 @@ class RecipientSchedule < ApplicationRecord Question.where(id: next_question_id).first end + def attempt_question_for_recipient_students(send_message: true, question: next_question) + return if recipient.opted_out? + return if question.nil? + + if !question.for_recipient_students? + return attempt_question(question: question) + end + + missing_students = [] + recipient_attempts = attempts.for_recipient(recipient).for_question(question) + recipient.students.each do |student| + if recipient_attempts.for_student(student).empty? + missing_students << student + end + end + + attempt = recipient.attempts.create( + schedule: schedule, + recipient_schedule: self, + question: question, + student: missing_students.first + ) + + if send_message && attempt.send_message + upcoming = upcoming_question_ids.try(:split, /,/) || [] + queued = queued_question_ids.try(:split, /,/) || [] + attempted = attempted_question_ids.try(:split, /,/) || [] + + if question.present? + question_id = [question.id.to_s] + upcoming = upcoming - question_id + if missing_students.length > 1 + queued += question_id + else + attempted += question_id + queued -= question_id + end + end + + update_attributes( + upcoming_question_ids: upcoming.empty? ? nil : upcoming.join(','), + attempted_question_ids: attempted.empty? ? nil : attempted.join(','), + queued_question_ids: queued.empty? ? nil : queued.join(','), + last_attempt_at: attempt.sent_at, + next_attempt_at: next_valid_attempt_time + ) + end + return attempt + end + def attempt_question(send_message: true, question: next_question) return if recipient.opted_out? unanswered_attempt = recipient.attempts.with_no_response.last return if question.nil? && unanswered_attempt.nil? - student = nil - if unanswered_attempt.nil? if question.for_recipient_students? - students = recipient.students - student = students.first - queued = queued_question_ids.try(:split, /,/) || [] - students[1...students.length].each do - queued << "#{question.id}:#{student.id}" - end - self.queued_question_ids = queued.join(',') + return attempt_question_for_recipient_students(question: question) end attempt = recipient.attempts.create( schedule: schedule, recipient_schedule: self, - question: question, - student: student + question: question ) end diff --git a/spec/lib/tasks/survey_rake_spec.rb b/spec/lib/tasks/survey_rake_spec.rb index 0c2c25aa..41b89572 100644 --- a/spec/lib/tasks/survey_rake_spec.rb +++ b/spec/lib/tasks/survey_rake_spec.rb @@ -200,6 +200,11 @@ describe "survey:attempt_questions" do end end + let(:students_recipient) { recipients[1] } + let(:students_recipient_schedule) { + recipient_schedule = students_recipient.recipient_schedules.for_schedule(schedule).first + } + describe 'With A FOR_CHILD Question Is Asked' do before :each do questions.first.update_attributes(for_recipient_students: true) @@ -215,23 +220,57 @@ describe "survey:attempt_questions" do end it 'should store queued questions when an attempt is made on first student' do - recipients.each do |recipient| - recipient_schedule = recipient.recipient_schedules.for_schedule(schedule).first - expect(recipient_schedule.queued_question_ids).to be_present - queued_question_ids = recipient_schedule.queued_question_ids.split(/,/) - expect(queued_question_ids.length).to eq(2) - expect(queued_question_ids.first).to eq("#{questions[0].id}:#{students[1].id}") - expect(queued_question_ids.last).to eq("#{questions[0].id}:#{students[2].id}") - end + expect(students_recipient_schedule.queued_question_ids).to be_present + queued_question_ids = students_recipient_schedule.queued_question_ids.split(/,/) + expect(queued_question_ids.length).to eq(1) + expect(queued_question_ids.first).to eq("#{questions[0].id}") + end + + it 'should set the next_attempt_at to now when attempt is made on first student' do + recipient.attempts.last.save_response(answer_index: 3) + expect(students_recipient_schedule.reload.next_attempt_at).to eq(Time.new) + end + + it 'should set the next_attempt_at to now when attempt is made on second student' do + students_recipient.attempts.last.save_response(answer_index: 3) + expect{students_recipient_schedule.attempt_question}.to change{students_recipient.attempts.count}.by(1) + expect(students_recipient_schedule.reload.queued_question_ids).to be_present + + attempt = students_recipient.attempts.last + expect(attempt.student).to eq(students_recipient.students[1]) + attempt.save_response(answer_index: 4) + expect(students_recipient_schedule.reload.next_attempt_at).to eq(Time.new) end - it 'should set the next_attempt_at to now when attempt is made on first student' + it 'should set the next_attempt_at in the future when an attempt is made on last student' do + students_recipient.attempts.last.save_response(answer_index: 3) + expect{students_recipient_schedule.attempt_question}.to change{students_recipient.attempts.count}.by(1) + expect(students_recipient_schedule.reload.queued_question_ids).to be_present + + attempt = students_recipient.attempts.last + expect(attempt.student).to eq(students_recipient.students[1]) + attempt.save_response(answer_index: 4) + expect(students_recipient_schedule.reload.next_attempt_at).to eq(Time.new) - it 'should set the next_attempt_at to now when attempt is made on second student' + expect{students_recipient_schedule.attempt_question}.to change{students_recipient.attempts.count}.by(1) + expect(students_recipient_schedule.reload.queued_question_ids).to be_nil + expect(students_recipient_schedule.reload.next_attempt_at).to_not eq(Time.new) - it 'should set the next_attempt_at in the future when an attempt is made on last student' + attempt = students_recipient.attempts.last + expect(attempt.student).to eq(students_recipient.students[2]) + attempt.save_response(answer_index: 2) + expect(students_recipient_schedule.reload.next_attempt_at).to_not eq(Time.new) + end it 'should mention the students name in the text' + + it 'resends the question about the same student if not responded to' + + it 'still sends when no students are present' + + it 'doesnt store any queued_question_ids when no students are present' + + it 'doesnt store any queued_question_ids when just one student is present' end describe 'With A General Question Is Asked' do