Include autenticazione, progetti isolati, mail marketing HTML con SMTP, test A/B e editor WYSIWYG. Co-authored-by: Cursor <cursoragent@cursor.com>
105 lines
2.9 KiB
Ruby
105 lines
2.9 KiB
Ruby
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
|