# == Schema Information # # Table name: accounts # # id :integer not null, primary key # auto_resolve_duration :integer # custom_attributes :jsonb # domain :string(100) # feature_flags :bigint default(0), not null # internal_attributes :jsonb not null # limits :jsonb # locale :integer default("en") # name :string not null # settings :jsonb # status :integer default("active") # support_email :string(100) # created_at :datetime not null # updated_at :datetime not null # # Indexes # # index_accounts_on_status (status) # class Account < ApplicationRecord # used for single column multi flags include FlagShihTzu include Reportable include Featurable include CacheKeys SETTINGS_PARAMS_SCHEMA = { 'type': 'object', 'properties': { 'auto_resolve_after': { 'type': %w[integer null], 'minimum': 10, 'maximum': 1_439_856 }, 'auto_resolve_message': { 'type': %w[string null] }, 'auto_resolve_ignore_waiting': { 'type': %w[boolean null] }, 'audio_transcriptions': { 'type': %w[boolean null] }, 'auto_resolve_label': { 'type': %w[string null] } }, 'required': [], 'additionalProperties': true }.to_json.freeze DEFAULT_QUERY_SETTING = { flag_query_mode: :bit_operator, check_for_column: false }.freeze validates :domain, length: { maximum: 100 } validates_with JsonSchemaValidator, schema: SETTINGS_PARAMS_SCHEMA, attribute_resolver: ->(record) { record.settings } store_accessor :settings, :auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting store_accessor :settings, :audio_transcriptions, :auto_resolve_label has_many :account_users, dependent: :destroy_async has_many :agent_bot_inboxes, dependent: :destroy_async has_many :agent_bots, dependent: :destroy_async has_many :api_channels, dependent: :destroy_async, class_name: '::Channel::Api' has_many :articles, dependent: :destroy_async, class_name: '::Article' has_many :assignment_policies, dependent: :destroy_async has_many :automation_rules, dependent: :destroy_async has_many :macros, dependent: :destroy_async has_many :campaigns, dependent: :destroy_async has_many :canned_responses, dependent: :destroy_async has_many :categories, dependent: :destroy_async, class_name: '::Category' has_many :contacts, dependent: :destroy_async has_many :conversations, dependent: :destroy_async has_many :csat_survey_responses, dependent: :destroy_async has_many :custom_attribute_definitions, dependent: :destroy_async has_many :custom_filters, dependent: :destroy_async has_many :dashboard_apps, dependent: :destroy_async has_many :data_imports, dependent: :destroy_async has_many :email_channels, dependent: :destroy_async, class_name: '::Channel::Email' has_many :facebook_pages, dependent: :destroy_async, class_name: '::Channel::FacebookPage' has_many :instagram_channels, dependent: :destroy_async, class_name: '::Channel::Instagram' has_many :hooks, dependent: :destroy_async, class_name: 'Integrations::Hook' has_many :inboxes, dependent: :destroy_async has_many :labels, dependent: :destroy_async has_many :line_channels, dependent: :destroy_async, class_name: '::Channel::Line' has_many :mentions, dependent: :destroy_async has_many :messages, dependent: :destroy_async has_many :notes, dependent: :destroy_async has_many :notification_settings, dependent: :destroy_async has_many :notifications, dependent: :destroy_async has_many :portals, dependent: :destroy_async, class_name: '::Portal' has_many :sms_channels, dependent: :destroy_async, class_name: '::Channel::Sms' has_many :teams, dependent: :destroy_async has_many :telegram_bots, dependent: :destroy_async has_many :telegram_channels, dependent: :destroy_async, class_name: '::Channel::Telegram' has_many :twilio_sms, dependent: :destroy_async, class_name: '::Channel::TwilioSms' has_many :twitter_profiles, dependent: :destroy_async, class_name: '::Channel::TwitterProfile' has_many :users, through: :account_users has_many :web_widgets, dependent: :destroy_async, class_name: '::Channel::WebWidget' has_many :webhooks, dependent: :destroy_async has_many :whatsapp_channels, dependent: :destroy_async, class_name: '::Channel::Whatsapp' has_many :working_hours, dependent: :destroy_async has_one_attached :contacts_export enum :locale, LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_1_code], key] }.to_h, prefix: true enum :status, { active: 0, suspended: 1 } scope :with_auto_resolve, -> { where("(settings ->> 'auto_resolve_after')::int IS NOT NULL") } before_validation :validate_limit_keys after_create_commit :notify_creation after_destroy :remove_account_sequences def agents users.where(account_users: { role: :agent }) end def administrators users.where(account_users: { role: :administrator }) end def all_conversation_tags # returns array of tags conversation_ids = conversations.pluck(:id) ActsAsTaggableOn::Tagging.includes(:tag) .where(context: 'labels', taggable_type: 'Conversation', taggable_id: conversation_ids) .map { |tagging| tagging.tag.name } end def webhook_data { id: id, name: name } end def inbound_email_domain domain.presence || GlobalConfig.get('MAILER_INBOUND_EMAIL_DOMAIN')['MAILER_INBOUND_EMAIL_DOMAIN'] || ENV.fetch('MAILER_INBOUND_EMAIL_DOMAIN', false) end def support_email super.presence || ENV.fetch('MAILER_SENDER_EMAIL') { GlobalConfig.get('MAILER_SUPPORT_EMAIL')['MAILER_SUPPORT_EMAIL'] } end def usage_limits { agents: ChatwootApp.max_limit.to_i, inboxes: ChatwootApp.max_limit.to_i } end def locale_english_name # the locale can also be something like pt_BR, en_US, fr_FR, etc. # the format is `_` # we need to extract the language code from the locale account_locale = locale&.split('_')&.first ISO_639.find(account_locale)&.english_name&.downcase || 'english' end private def notify_creation Rails.configuration.dispatcher.dispatch(ACCOUNT_CREATED, Time.zone.now, account: self) end trigger.after(:insert).for_each(:row) do "execute format('create sequence IF NOT EXISTS conv_dpid_seq_%s', NEW.id);" end trigger.name('camp_dpid_before_insert').after(:insert).for_each(:row) do "execute format('create sequence IF NOT EXISTS camp_dpid_seq_%s', NEW.id);" end def validate_limit_keys # method overridden in enterprise module end def remove_account_sequences ActiveRecord::Base.connection.exec_query("drop sequence IF EXISTS camp_dpid_seq_#{id}") ActiveRecord::Base.connection.exec_query("drop sequence IF EXISTS conv_dpid_seq_#{id}") end end Account.prepend_mod_with('Account') Account.prepend_mod_with('Account::PlanUsageAndLimits') Account.include_mod_with('Concerns::Account') Account.include_mod_with('Audit::Account')