vegantech/sims

View on GitHub
app/models/checklist.rb

Summary

Maintainability
A
3 hrs
Test Coverage
# == Schema Information
# Schema version: 20101101011500
#
# Table name: checklists
#
#  id                      :integer(4)      not null, primary key
#  checklist_definition_id :integer(4)
#  from_tier               :integer(4)
#  student_id              :integer(4)
#  promoted                :boolean(1)
#  user_id                 :integer(4)
#  is_draft                :boolean(1)      default(TRUE)
#  district_id             :integer(4)
#  created_at              :datetime
#  updated_at              :datetime
#

class Checklist < ActiveRecord::Base
  DISTRICT_PARENT = :checklist_definition
  has_many :answers, :dependent => :destroy
  belongs_to :checklist_definition, :include => {:question_definitions => {:element_definitions => :answer_definitions}}
  belongs_to :student
  belongs_to :teacher, :class_name => "User", :foreign_key => :user_id  #e xplicitly needed for validation
  belongs_to :district
  belongs_to :tier, :foreign_key => :from_tier
  has_one :recommendation,:dependent => :destroy
  validate :cannot_pass_if_draft
  validates_presence_of :student_id, :user_id, :from_tier

  delegate :recommendation_definition, :to => :checklist_definition
  delegate :recommendation_definition_id, :to => :checklist_definition
  attr_accessor :skip_cache
  attr_reader :build_errors
  define_statistic :count , :count => :all
  define_statistic :count_of_districts, :count => :all, :column_name => 'distinct district_id'
  after_update :remove_deleted_answers
  before_validation :assign_associated_from_student, :on => :create
  attr_protected :district_id


  STATUS = {
          :unknown => "UNKNOWN_STATUS",
          :draft => "Draft, make changes and submit",
          :missing_rec => "Submitted, but missing recommendation",
          :nonadvancing => "Checklist submitted, continue working at same tier",
          :optional_checklist => "Optional Checklist Completed"
        }

  #  has_many :answers_with_includes, :class_name => "Answer",
  # :include => {:answer_definition=>:element_definition}
  attr_accessor :score_results, :deletable, :needs_recommendation, :fake_edit
  @checklist_definition = {}

  def checklist_definition_cache
    return checklist_definition   #
    if @skip_cache then
      checklist_definition
    else
      @checklist_definition[self.checklist_definition_id] ||= checklist_definition
    end
  end

   def status
     @deletable=true
     if is_draft? then
       STATUS[:draft]
     elsif needs_recommendation?
       @needs_recommendation=true
       STATUS[:missing_rec]
     elsif recommendation_definition_id.blank?
       STATUS[:optional_checklist]
     else
       @deletable=false
       recommendation.status
     end
   end

   def pending?
     previous_checklist and (previous_checklist.is_draft? or previous_checklist.needs_recommendation?)
   end

   def missing_checklist_definition?
      checklist_definition.blank?
   end

   def self.max_tier
   end


  def self.new_from_teacher(teacher)
    #this builds a new checklist and scores it by copying the old values?
    checklist = Checklist.new(:teacher => teacher)
    return nil unless checklist.student
    checklist.checklist_definition = checklist.student.checklist_definition
    checklist.tier = checklist.student.max_tier
    checklist.district_id = checklist.student.district_id

    c = checklist.student.checklists.find_by_checklist_definition_id(checklist.checklist_definition_id, :order => "created_at DESC")

    if c
      c.answers.each {|e| checklist.answers.build e.attributes.except("checklist_id")}
      c.score_checklist if c.show_score?(false)
      checklist.score_results = c.score_results
    end
    checklist
  end

  def self.find_and_score(checklist_id)
    c=find_by_id(checklist_id,:include=>{:answers=>:answer_definition})
    c.score_checklist if c && c.show_score?
    c
  end

  def score_checklist
    #for demo purpose, answering the second question will pass the checklist
    if student and student.last_name=="Flag" and student.first_name="Every" and answers.find_by_answer_definition_id(6) then
      self.promoted=true
      return true
    end

    @score_results = ChecklistScorer.new(self).score
    self.promoted = @score_results.blank?
  end

  def element_definitions_for_answers
    @edfa||= answers.collect(&:answer_definition).collect(&:element_definition)
  end

  def text
    checklist_definition_cache.text
  end

  def directions
    checklist_definition_cache.directions
  end

  def question_definitions
    checklist_definition_cache.question_definitions
  end

  def previous_answers_for(answer_definition)
#    student.checklist_answers_for_student.find_all_by_answer_definition_id(answer_definition.answer_definition_id,:conditions=>["checklists.created_at < ?", created_at], :order=> 'created_at ASC')

    Answer.find(:all,
                :conditions => ['answer_definition_id = ? and checklist_id IN(?) and created_at < ? ',
                                answer_definition.id,
                                student.checklists, created_at ||Time.now],
                :order => 'created_at ASC')
  end

  def previous_answer_for(element_definition)
    recent_checklist = student.checklists.find(:first,:order=>"created_at DESC, id DESC")
    recent_checklist.answers.find_all_by_element_definition(element_definition)[0]  unless recent_checklist.blank?

#   student.checklists.collect(&:answers).flatten.select{|answer| answer.answer_definition.element_definition == element_definition}.sort{|answer| answer.created_at}[0]
  end

  def editable?
    @editable ||= self.is_draft? || self.recommendation.blank? || student.checklists.last == self
  end

  def show_score?(check_previous=true)
    @show_score=false
    if !promoted and recommendation and recommendation.should_advance
      @show_score=true
    elsif check_previous
      prev_chk=previous_checklist
      @show_sore= prev_chk and prev_chk.show_score?
    end
    @show_score
#   @show_score = !promoted and recommendation and recommendation.should_advance? or (check_previous and previous_checklist.show_score?(false) )
  end

  def previous_checklist
    @previous_checklist ||= Checklist.find_by_user_id(self.student_id, :order=>"created_at DESC",:conditions=>["id <> ? and created_at < ?",self.id || -1, self.created_at || Time.now])
  end

  def needs_recommendation?
    recommendation.blank?  && recommendation_definition_id && !is_draft?
  end

#used to support actually editing a checklist instead of creating a new version and deleting! the old one!!!
#TODO Clean this up when I finish up the view changes
  #
  def can_build?
    @build_errors = []
    @build_errors <<("No tiers available.  Using the checklist requires at least one tier.") unless  district.tiers.any?
    @build_errors << ("No checklist available.  Have the content builder create one.") unless district.checklist_definitions.any?
    @build_errors <<("Please submit/edit or delete the already started checklist first") if pending?
    @build_errors.blank?
  end
  def commit=(ignore)
    self.is_draft = false
  end

  def save_draft=(ignore)
    self.is_draft = true
  end

  def element_definition=(element_definition_hash)
    @answer_definition_ids = []
    element_definition_hash.each do |element_definition_id, answer|
      element_definition = ElementDefinition.find(element_definition_id)
      if ['scale','applicable'].include?(element_definition.kind)
        answer_hash = {:answer_definition_id => answer.to_i}
      elsif ['comment','sa'].include?(element_definition.kind) && answer['text'].present?
          answer_hash = { :answer_definition_id => answer['id'].to_i,
                                  :text => answer['text']}
      else
        next  #text is empty
      end
      (answers.find_by_answer_definition_id(answer_hash[:answer_definition_id]) || answers.build).attributes=answer_hash
      @answer_definition_ids << answer_hash[:answer_definition_id]
    end

  end

  private

  def remove_deleted_answers
    if @answer_definition_ids.present?
      answers.each{|a| a.destroy unless @answer_definition_ids.include?(a.answer_definition_id) }
    end
  end

  def assign_associated_from_student
    self.checklist_definition = student.checklist_definition if checklist_definition.blank?
    self.tier = student.max_tier if tier.blank?
    self.district_id = student.district_id if district.blank?
  end


  #End of refactoring for edit/create  These might change when I refactor the view ^^^^^

  def cannot_pass_if_draft
    errors.add(:is_draft,"Checklist was not submitted") if promoted && is_draft?
  end

  def cannot_pass_unless_recommended
    errors.add(:recommendation, "Must have recommendation") if  promoted and  needs_recommendation?
  end
end