mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.6 KiB
112 lines
3.6 KiB
# frozen_string_literal: true
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: cohorts
|
|
#
|
|
# id :bigint not null, primary key
|
|
# cohort_metadata :jsonb
|
|
# deleted_at :datetime
|
|
# finalized_at :datetime
|
|
# name :string not null
|
|
# program_type :string not null
|
|
# required_student_uploads :jsonb
|
|
# sponsor_completed_at :datetime
|
|
# sponsor_email :string not null
|
|
# status :string default("draft")
|
|
# students_completed_at :datetime
|
|
# tp_signed_at :datetime
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# institution_id :bigint not null
|
|
# template_id :bigint not null
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_cohorts_on_institution_id (institution_id)
|
|
# index_cohorts_on_institution_id_and_status (institution_id,status)
|
|
# index_cohorts_on_sponsor_email (sponsor_email)
|
|
# index_cohorts_on_template_id (template_id)
|
|
#
|
|
# Foreign Keys
|
|
#
|
|
# fk_rails_... (institution_id => institutions.id)
|
|
# fk_rails_... (template_id => templates.id)
|
|
#
|
|
class Cohort < ApplicationRecord
|
|
include SoftDeletable
|
|
include AASM
|
|
|
|
# Strip whitespace from string attributes
|
|
strip_attributes only: %i[name program_type sponsor_email]
|
|
|
|
# Associations
|
|
belongs_to :institution
|
|
belongs_to :template
|
|
has_many :cohort_enrollments, dependent: :destroy
|
|
has_many :submissions, through: :cohort_enrollments
|
|
|
|
# Validations
|
|
validates :name, presence: true
|
|
validates :program_type, presence: true, inclusion: { in: %w[learnership internship candidacy] }
|
|
validates :sponsor_email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
|
|
validates :status, inclusion: { in: %w[draft active completed] }
|
|
|
|
# Scopes
|
|
# Note: 'active' scope is provided by SoftDeletable concern
|
|
scope :draft, -> { where(status: 'draft') }
|
|
scope :active_status, -> { where(status: 'active') }
|
|
scope :completed, -> { where(status: 'completed') }
|
|
scope :ready_for_sponsor, -> { where(status: 'active').where.not(students_completed_at: nil) }
|
|
|
|
# State Machine (Basic 3-state version for Story 1.2)
|
|
# Enhanced 7-state machine will be implemented in Story 2.2
|
|
aasm column: :status do
|
|
state :draft, initial: true
|
|
state :active
|
|
state :completed
|
|
|
|
# Transition from draft to active (TP signs)
|
|
event :activate do
|
|
transitions from: :draft, to: :active, after: :mark_tp_signed
|
|
end
|
|
|
|
# Transition from active to completed (all phases done)
|
|
event :complete do
|
|
transitions from: :active, to: :completed, after: :mark_finalized
|
|
end
|
|
end
|
|
|
|
# Check if all students have completed their submissions
|
|
# @return [Boolean] true if all student enrollments are completed
|
|
def all_students_completed?
|
|
return false if cohort_enrollments.students.empty?
|
|
|
|
cohort_enrollments.students.all?(&:completed?)
|
|
end
|
|
|
|
# Check if sponsor access is ready (TP signed and students completed)
|
|
# @return [Boolean] true if ready for sponsor review
|
|
def sponsor_access_ready?
|
|
active? && tp_signed_at.present? && all_students_completed?
|
|
end
|
|
|
|
# Check if TP can sign (cohort is in draft state)
|
|
# @return [Boolean] true if TP can sign
|
|
def tp_can_sign?
|
|
draft?
|
|
end
|
|
|
|
private
|
|
|
|
# Callback: Mark TP signing timestamp
|
|
def mark_tp_signed
|
|
update_column(:tp_signed_at, Time.current)
|
|
end
|
|
|
|
# Callback: Mark finalization timestamp
|
|
def mark_finalized
|
|
update_column(:finalized_at, Time.current)
|
|
end
|
|
end
|