Commit iniziale di eminuxCRM: CRM Rails con pipeline, campagne email e Docker.
Include autenticazione, progetti isolati, mail marketing HTML con SMTP, test A/B e editor WYSIWYG. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
class Organization < ApplicationRecord
|
||||
include Auditable
|
||||
|
||||
belongs_to :assigned_user, class_name: "User", optional: true
|
||||
|
||||
has_many :organization_projects, dependent: :destroy
|
||||
has_many :projects, through: :organization_projects
|
||||
has_many :contacts, dependent: :destroy
|
||||
has_many :opportunities, dependent: :destroy
|
||||
has_many :activities, dependent: :destroy
|
||||
has_many :tasks, dependent: :destroy
|
||||
has_many :mailing_recipients, dependent: :destroy
|
||||
|
||||
has_one :primary_contact, -> { where(primary_contact: true) }, class_name: "Contact", inverse_of: :organization
|
||||
|
||||
validates :name, presence: true
|
||||
validates :status, inclusion: { in: Catalog::ORGANIZATION_STATUSES.keys }
|
||||
validates :organization_type, inclusion: { in: Catalog::ORGANIZATION_TYPES.keys }
|
||||
validates :lead_source, inclusion: { in: Catalog::LEAD_SOURCES.keys }, allow_blank: true
|
||||
validates :team_gender, inclusion: { in: Catalog::TEAM_GENDERS.keys }, allow_blank: true
|
||||
validates :streaming_status, inclusion: { in: Catalog::STREAMING_STATUSES.keys }, allow_blank: true
|
||||
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }, allow_blank: true
|
||||
validate :must_have_at_least_one_project
|
||||
before_validation :assign_current_project_if_needed, on: :create
|
||||
|
||||
scope :prospects, -> { where(status: "prospect") }
|
||||
scope :customers, -> { where(status: %w[active_customer inactive_customer]) }
|
||||
scope :active_customers, -> { where(status: "active_customer") }
|
||||
scope :for_project, ->(project) {
|
||||
return none if project.nil?
|
||||
|
||||
joins(:organization_projects).where(organization_projects: { project_id: project.id }).distinct
|
||||
}
|
||||
scope :search, ->(query) {
|
||||
return all if query.blank?
|
||||
|
||||
q = "%#{sanitize_sql_like(query.strip)}%"
|
||||
left_joins(:contacts).where(
|
||||
"organizations.name ILIKE :q OR organizations.city ILIKE :q OR organizations.email ILIKE :q OR organizations.phone ILIKE :q OR organizations.website ILIKE :q OR contacts.first_name ILIKE :q OR contacts.last_name ILIKE :q OR contacts.email ILIKE :q OR contacts.phone ILIKE :q OR contacts.mobile ILIKE :q",
|
||||
q: q
|
||||
).distinct
|
||||
}
|
||||
|
||||
def status_label
|
||||
Catalog.label_for(Catalog::ORGANIZATION_STATUSES, status)
|
||||
end
|
||||
|
||||
def organization_type_label
|
||||
Catalog.label_for(Catalog::ORGANIZATION_TYPES, organization_type)
|
||||
end
|
||||
|
||||
def lead_source_label
|
||||
Catalog.label_for(Catalog::LEAD_SOURCES, lead_source)
|
||||
end
|
||||
|
||||
def team_gender_label
|
||||
Catalog.label_for(Catalog::TEAM_GENDERS, team_gender)
|
||||
end
|
||||
|
||||
def streaming_status_label
|
||||
Catalog.label_for(Catalog::STREAMING_STATUSES, streaming_status)
|
||||
end
|
||||
|
||||
def campaign_opportunity(project = nil)
|
||||
list = opportunities.to_a
|
||||
list = list.select { |opp| opp.project_id == project.id } if project
|
||||
list.max_by(&:updated_at)
|
||||
end
|
||||
|
||||
def primary_pipeline_stage(project = nil)
|
||||
scope = opportunities
|
||||
scope = scope.where(project_id: project.id) if project
|
||||
scope.open_stage.order(updated_at: :desc).first&.pipeline_stage ||
|
||||
scope.order(updated_at: :desc).first&.pipeline_stage
|
||||
end
|
||||
|
||||
def next_pending_task
|
||||
tasks.pending.order(:due_at).first
|
||||
end
|
||||
|
||||
def last_activity_at
|
||||
activities.maximum(:happened_at)
|
||||
end
|
||||
|
||||
def days_since_last_activity
|
||||
return nil unless last_activity_at
|
||||
|
||||
((Time.current - last_activity_at) / 1.day).floor
|
||||
end
|
||||
|
||||
def mark_as_active_customer!
|
||||
update!(status: "active_customer") if status != "active_customer"
|
||||
end
|
||||
|
||||
def ensure_in_project!(project)
|
||||
return if project.nil?
|
||||
return if projects.exists?(project.id)
|
||||
|
||||
projects << project
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign_current_project_if_needed
|
||||
return if organization_projects.any? || project_ids.reject(&:blank?).any?
|
||||
return unless Current.project
|
||||
|
||||
organization_projects.build(project: Current.project)
|
||||
end
|
||||
|
||||
def must_have_at_least_one_project
|
||||
return if organization_projects.any? || project_ids.reject(&:blank?).any?
|
||||
|
||||
errors.add(:projects, "seleziona almeno un progetto")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user