mmibordeaux/teach

View on GitHub
app/models/year.rb

Summary

Maintainability
C
7 hrs
Test Coverage
# == Schema Information
#
# Table name: years
#
#  id         :integer          not null, primary key
#  year       :integer
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class Year < ActiveRecord::Base

  has_many :projects
  has_many :objectives, through: :projects

  def self.create_necessary
    year = Date.today.year
    where(year: year-1).first_or_create
    where(year: year).first_or_create
    where(year: year+1).first_or_create
    where(year: year+2).first_or_create
    where(year: year+3).first_or_create
  end

  def self.current
    create_necessary
    year = Date.today.year
    year += 1 if Date.today.month >= 7
    where(year: year).first
  end

  def from
    @from ||= Date.new year-1, 9
  end

  def to
    @to ||= from + 1.year - 1.day
  end

  def first_year_promotion
    y = year < 2022 ? year+1 : year+2
    Promotion.where(year: y).first
  end

  def second_year_promotion
    y = year < 2023 ? year : year+1
    Promotion.where(year: y).first
  end

  def third_year_promotion
    return if year < 2024
    Promotion.where(year: year).first
  end

  def promotions
    [first_year_promotion, second_year_promotion]
  end

  def promotion_for_semester(semester)
    case semester.id
    when 1, 2
      first_year_promotion
    when 3, 4
      second_year_promotion
    when 5, 6
      third_year_promotion
    end
  end

  def involvements
    if @involvements.nil?
      first_year_promotion_id = first_year_promotion.nil? ? nil : first_year_promotion.id
      first_year_module_ids = TeachingModule.where(semester_id: [1, 2]).pluck(:id)
      second_year_promotion_id = second_year_promotion.nil? ? nil : second_year_promotion.id
      second_year_module_ids = TeachingModule.where(semester_id: [3, 4]).pluck(:id)
      @involvements = Involvement
                        .where( '(promotion_id = ? AND teaching_module_id IN (?)) OR (promotion_id = ? AND teaching_module_id IN (?))',
                                first_year_promotion_id, first_year_module_ids,
                                second_year_promotion_id, second_year_module_ids)
    end
    @involvements
  end

  def projects_with_user_involved(user)
    involvements_for_user(user).collect(&:project).uniq.compact.to_ary.sort_by(&:week_number)
  end

  def users
    @users ||= (users_with_involvements + users_with_events).uniq.sort_by { |user| user&.last_name }
  end

  # Planned (involvements)

  def involvements_for_user(user)
    involvements.where(user: user)
  end

  def involvements_for_teaching_module(teaching_module)
    involvements.where(teaching_module: teaching_module)
  end

  def involvements_for_resource(resource)
    involvements.where(resource: resource)
  end

  def planned_student_hours
    involvements.collect(&:student_hours).sum.round(2)
  end

  def planned_teacher_hours
    involvements.collect(&:teacher_hours).sum.round(2)
  end

  def planned_hours_for(user, kind = :teacher_hours)
    involvements_for_user(user).sum(kind)
  end

  def planned_teaching_modules_for(user)
    involvements_for_user(user).collect(&:teaching_module).uniq.sort_by { |tm| tm.code }
  end

  def planned_delta_for(user)
    return 0 if user.hours.nil?
    planned_hours_for(user) - user.hours
  end

  def planned_hours_for_teaching_module(teaching_module, kind = :teacher_hours)
    involvements_for_teaching_module(teaching_module).sum(kind)
  end

  def planned_hours_for_resource(resource, kind = :teacher_hours)
    involvements_for_resource(resource).sum(kind)
  end

  def planned_hours_for_teaching_module_and_user(teaching_module, user, kind = :teacher_hours)
    involvements_for_user(user).where(teaching_module: teaching_module).sum(kind)
  end

  # Scheduled (events)

  def scheduled_student_hours
    @scheduled_student_hours ||= events.sum(:student_hours)
  end

  def scheduled_teacher_hours
    @scheduled_teacher_hours ||= events.sum(:teacher_hours)
  end

  def scheduled_student_hours_by_tenured_teachers
    @scheduled_student_hours_by_tenured_teachers ||= events.joins(:user).where('users.tenured = true').sum(:student_hours)
  end

  def scheduled_student_hours_by_non_tenured_teachers
    @scheduled_student_hours_by_non_tenured_teachers ||= events.joins(:user).where('users.tenured = false').sum(:student_hours)
  end

  def scheduled_student_hours_non_tenured_ratio
    return 0 if scheduled_student_hours.zero?
    100.0 * scheduled_student_hours_by_non_tenured_teachers / scheduled_student_hours
  end

  def scheduled_hours_for(user, kind = nil)
    events_for(user, kind).sum(:duration)
  end

  def scheduled_hours_ponderated_for(user)
    cm = events_for(user).cm.sum(:duration) * Involvement::COST_RATIO_CM
    td = events_for(user).td.sum(:duration) * Involvement::COST_RATIO_TD
    tp = events_for(user).tp.sum(:duration) * Involvement::COST_RATIO_TP
    cm + td + tp
  end

  def scheduled_teacher_hours_for(user, kind = nil)
    events_for(user, kind).sum(:teacher_hours)
  end

  def scheduled_student_hours_for(user, kind = nil)
    events_for(user, kind).sum(:student_hours)
  end

  def events
    @events ||= Event.where('date >= ? AND date < ?', from, to)
  end

  def events_for(user, kind = nil)
    events = user.events.where('date >= ? AND date < ?', from, to)
    events = events.send(kind) if kind
    events
  end

  def scheduled_teaching_modules_for(user)
    teaching_modules = events_for(user).collect(&:teaching_module).uniq.compact
    teaching_modules.sort_by { |tm| tm.code }
  end

  def scheduled_hours_for_teaching_module(teaching_module, kind_of_hours = nil)
    e = events.where(teaching_module: teaching_module)
    e = e.send(kind_of_hours) if kind_of_hours
    e.sum(:student_hours)
  end

  def scheduled_hours_for_teaching_module_and_user(teaching_module, user, kind = :teacher_hours)
    events = events_for(user).where(teaching_module: teaching_module)
    case kind
    when :hours_cm
      events = events.cm
    when :hours_td
      events = events.td
    when :hours_tp
      events = events.tp
    end
    events.sum :duration
  end

  def scheduled_resource_for(user)
    resources = events_for(user).collect(&:resource).uniq.compact
    resources.sort_by { |r| r.code }
  end

  def scheduled_hours_for_resource(resource, kind_of_hours = nil)
    e = events.where(resource: resource)
    e = e.send(kind_of_hours) if kind_of_hours
    e.sum(:student_hours)
  end

  def scheduled_hours_for_resource_and_user(resource, user, kind = :teacher_hours)
    events = events_for(user).where(resource: resource)
    case kind
    when :hours_cm
      events = events.cm
    when :hours_td
      events = events.td
    when :hours_tp
      events = events.tp
    end
    events.sum :duration
  end

  def scheduled_delta_for(user)
    return 0 if user.hours.nil?
    scheduled_hours_for(user) - user.hours
  end

  def to_s
    "#{year-1} - #{year}"
  end

  protected

  def users_with_involvements
    involvements.where.not(user: nil).collect(&:user)
  end

  def users_with_events
    events.where.not(user: nil).collect(&:user)
  end
end