KyivKrishnaAcademy/ved_akadem_students

View on GitHub
app/models/concerns/class_schedule_custom_validations.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
module ClassScheduleCustomValidations
  extend ActiveSupport::Concern

  included do
    validate :enough_roominess, :duration, :teacher_availability, :classroom_availability, :academic_groups_availability
  end

  private

  def enough_roominess
    return if classroom.blank? || academic_groups.none?

    required_roominess = academic_groups.map { |ag| ag.active_students.count }.inject(:+)

    return if required_roominess <= classroom.roominess

    errors.add(:classroom,
               I18n.t('activerecord.errors.models.class_schedule.attributes.classroom.roominess',
                      actual: classroom.roominess,
                      required: required_roominess))
  end

  def duration
    return if finish_time.blank? || start_time.blank?
    return if finish_time - start_time < 1.day && finish_time - start_time >= 10.minutes && start_time < finish_time

    errors.add(:start_time, I18n.t('activerecord.errors.models.class_schedule.wrong_times'))
    errors.add(:finish_time, I18n.t('activerecord.errors.models.class_schedule.wrong_times'))
  end

  def teacher_availability
    return if teacher_profile.blank?
    return if obj_availability(teacher_profile_id: teacher_profile.id)

    errors.add(:teacher_profile,
               I18n.t('activerecord.errors.models.class_schedule.attributes.teacher_profile.availability'))
  end

  def classroom_availability
    return if classroom.blank?
    return if obj_availability(classroom_id: classroom.id)

    errors.add(:classroom, I18n.t('activerecord.errors.models.class_schedule.attributes.classroom.availability'))
  end

  def academic_groups_availability
    return if academic_groups.none?

    unavailable_groups = AcademicGroup
                           .joins(:class_schedules)
                           .where(academic_group_schedules: { academic_group_id: academic_groups.map(&:id) })
                           .where.not(academic_group_schedules: { class_schedule_id: id })
                           .where(
                             '(class_schedules.start_time, class_schedules.finish_time) OVERLAPS (:start, :finish)',
                             start: start_time,
                             finish: finish_time
                           )
                           .distinct

    return if unavailable_groups.none?

    errors.add(:academic_groups,
               I18n.t('activerecord.errors.models.class_schedule.attributes.academic_groups.availability',
                      groups: unavailable_groups.pluck(:title).sort.join(', ')))
  end

  def obj_availability(params)
    ClassSchedule
      .where(params)
      .where.not(id: id)
      .find_by(
        '(start_time, finish_time) OVERLAPS (:start, :finish)',
        start: start_time,
        finish: finish_time
      )
      .blank?
  end
end