Restructure omni services and add Chatwoot research snapshot

This commit is contained in:
Ruslan Bakiev
2026-02-21 11:11:27 +07:00
parent edea7a0034
commit b73babbbf6
7732 changed files with 978203 additions and 32 deletions

View File

@@ -0,0 +1,62 @@
class MessageTemplates::HookExecutionService
pattr_initialize [:message!]
def perform
return if conversation.last_incoming_message.blank?
return if message.auto_reply_email?
trigger_templates
end
private
delegate :inbox, :conversation, to: :message
delegate :contact, to: :conversation
def trigger_templates
::MessageTemplates::Template::OutOfOffice.new(conversation: conversation).perform if should_send_out_of_office_message?
::MessageTemplates::Template::Greeting.new(conversation: conversation).perform if should_send_greeting?
::MessageTemplates::Template::EmailCollect.new(conversation: conversation).perform if inbox.enable_email_collect && should_send_email_collect?
end
def should_send_out_of_office_message?
return false if conversation.campaign.present?
# should not send if its a tweet message
return false if conversation.tweet?
# should not send for outbound messages
return false unless message.incoming?
# prevents sending out-of-office message if an agent has sent a message in last 5 minutes
# ensures better UX by not interrupting active conversations at the end of business hours
return false if conversation.messages.outgoing.where(private: false).exists?(['created_at > ?', 5.minutes.ago])
inbox.out_of_office? && conversation.messages.today.template.empty? && inbox.out_of_office_message.present?
end
def first_message_from_contact?
conversation.messages.outgoing.count.zero? && conversation.messages.template.count.zero?
end
def should_send_greeting?
return false if conversation.campaign.present?
# should not send if its a tweet message
return false if conversation.tweet?
first_message_from_contact? && inbox.greeting_enabled? && inbox.greeting_message.present?
end
def email_collect_was_sent?
conversation.messages.where(content_type: 'input_email').present?
end
# TODO: we should be able to reduce this logic once we have a toggle for email collect messages
def should_send_email_collect?
return false if conversation.campaign.present?
!contact_has_email? && inbox.web_widget? && !email_collect_was_sent?
end
def contact_has_email?
contact.email
end
end
MessageTemplates::HookExecutionService.prepend_mod_with('MessageTemplates::HookExecutionService')

View File

@@ -0,0 +1,42 @@
class MessageTemplates::Template::AutoResolve
pattr_initialize [:conversation!]
def perform
return if conversation.account.auto_resolve_message.blank?
if within_messaging_window?
conversation.messages.create!(auto_resolve_message_params)
else
create_auto_resolve_not_sent_activity_message
end
end
private
delegate :contact, :account, to: :conversation
delegate :inbox, to: :message
def within_messaging_window?
conversation.can_reply?
end
def create_auto_resolve_not_sent_activity_message
content = I18n.t('conversations.activity.auto_resolve.not_sent_due_to_messaging_window')
activity_message_params = {
account_id: conversation.account_id,
inbox_id: conversation.inbox_id,
message_type: :activity,
content: content
}
::Conversations::ActivityMessageJob.perform_later(conversation, activity_message_params) if content
end
def auto_resolve_message_params
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content: account.auto_resolve_message
}
end
end

View File

@@ -0,0 +1,40 @@
class MessageTemplates::Template::CsatSurvey
pattr_initialize [:conversation!]
def perform
ActiveRecord::Base.transaction do
conversation.messages.create!(csat_survey_message_params)
end
end
private
delegate :contact, :account, :inbox, to: :conversation
def message_content
return I18n.t('conversations.templates.csat_input_message_body') if csat_config.blank? || csat_config['message'].blank?
csat_config['message']
end
def csat_survey_message_params
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content_type: :input_csat,
content: message_content,
content_attributes: content_attributes
}
end
def csat_config
inbox.csat_config || {}
end
def content_attributes
{
display_type: csat_config['display_type'] || 'emoji'
}
end
end

View File

@@ -0,0 +1,43 @@
class MessageTemplates::Template::EmailCollect
pattr_initialize [:conversation!]
def perform
ActiveRecord::Base.transaction do
conversation.messages.create!(ways_to_reach_you_message_params)
conversation.messages.create!(email_input_box_template_message_params)
end
rescue StandardError => e
ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception
true
end
private
delegate :contact, :account, to: :conversation
delegate :inbox, to: :message
def ways_to_reach_you_message_params
content = I18n.t('conversations.templates.ways_to_reach_you_message_body',
account_name: account.name)
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content: content
}
end
def email_input_box_template_message_params
content = I18n.t('conversations.templates.email_input_box_message_body',
account_name: account.name)
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content_type: :input_email,
content: content
}
end
end

View File

@@ -0,0 +1,28 @@
class MessageTemplates::Template::Greeting
pattr_initialize [:conversation!]
def perform
ActiveRecord::Base.transaction do
conversation.messages.create!(greeting_message_params)
end
rescue StandardError => e
ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception
true
end
private
delegate :contact, :account, to: :conversation
delegate :inbox, to: :message
def greeting_message_params
content = @conversation.inbox&.greeting_message
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content: content
}
end
end

View File

@@ -0,0 +1,36 @@
class MessageTemplates::Template::OutOfOffice
pattr_initialize [:conversation!]
def self.perform_if_applicable(conversation)
inbox = conversation.inbox
return unless inbox.out_of_office?
return if inbox.out_of_office_message.blank?
new(conversation: conversation).perform
end
def perform
ActiveRecord::Base.transaction do
conversation.messages.create!(out_of_office_message_params)
end
rescue StandardError => e
ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception
true
end
private
delegate :contact, :account, to: :conversation
delegate :inbox, to: :message
def out_of_office_message_params
content = @conversation.inbox&.out_of_office_message
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content: content
}
end
end