class Task < ApplicationRecord include Auditable belongs_to :organization belongs_to :contact, optional: true belongs_to :opportunity, optional: true belongs_to :assigned_user, class_name: "User", optional: true validates :title, :due_at, presence: true validates :priority, inclusion: { in: Catalog::TASK_PRIORITIES.keys } validates :task_type, inclusion: { in: Catalog::TASK_TYPES.keys } validates :status, inclusion: { in: Catalog::TASK_STATUSES.keys } scope :pending, -> { where(status: "pending") } scope :completed, -> { where(status: "completed") } scope :overdue, -> { pending.where("due_at < ?", Time.zone.now.beginning_of_day) } scope :due_today, -> { pending.where(due_at: Time.zone.now.all_day) } scope :upcoming, ->(days = 7) { pending.where(due_at: Time.zone.now.tomorrow.beginning_of_day..(Time.zone.now + days.days).end_of_day) } scope :ordered, -> { order(Arel.sql("CASE priority WHEN 'urgent' THEN 0 WHEN 'high' THEN 1 WHEN 'normal' THEN 2 ELSE 3 END"), :due_at) } scope :for_project, ->(project) { return none if project.nil? where( id: left_joins(:opportunity) .joins("INNER JOIN organization_projects ON organization_projects.organization_id = tasks.organization_id") .where( "organization_projects.project_id = :pid OR opportunities.project_id = :pid", pid: project.id ) .select("tasks.id") .distinct ) } def priority_label Catalog.label_for(Catalog::TASK_PRIORITIES, priority) end def task_type_label Catalog.label_for(Catalog::TASK_TYPES, task_type) end def status_label Catalog.label_for(Catalog::TASK_STATUSES, status) end def overdue? pending? && due_at < Time.zone.now.beginning_of_day end def due_today? pending? && due_at.to_date == Time.zone.today end def pending? status == "pending" end def completed? status == "completed" end def complete!(user: Current.user, create_activity: true) return false unless pending? transaction do update!(status: "completed", completed_at: Time.current, updated_by: user) create_completion_activity!(user) if create_activity && user end true end private def create_completion_activity!(user) activities_attrs = { activity_type: activity_type_for_task, subject: title, description: description, happened_at: Time.current, user: user, organization: organization, contact: contact, opportunity: opportunity, created_by: user, updated_by: user } Activity.create!(activities_attrs) end def activity_type_for_task { "follow_up" => "follow_up", "call" => "call", "email" => "email_sent", "meeting" => "meeting", "demo" => "demo", "proposal" => "proposal_sent", "generic" => "other" }.fetch(task_type, "other") end end