diff --git a/app/models/concerns/activity_message_handler.rb b/app/models/concerns/activity_message_handler.rb index 54e58b4d9..0d6741c7a 100644 --- a/app/models/concerns/activity_message_handler.rb +++ b/app/models/concerns/activity_message_handler.rb @@ -5,6 +5,7 @@ module ActivityMessageHandler include LabelActivityMessageHandler include SlaActivityMessageHandler include TeamActivityMessageHandler + include CsatActivityMessageHandler private diff --git a/app/models/concerns/csat_activity_message_handler.rb b/app/models/concerns/csat_activity_message_handler.rb new file mode 100644 index 000000000..7a2488c4d --- /dev/null +++ b/app/models/concerns/csat_activity_message_handler.rb @@ -0,0 +1,8 @@ +module CsatActivityMessageHandler + extend ActiveSupport::Concern + + def create_csat_not_sent_activity_message + content = I18n.t('conversations.activity.csat.not_sent_due_to_messaging_window') + ::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content + end +end diff --git a/app/services/message_templates/hook_execution_service.rb b/app/services/message_templates/hook_execution_service.rb index a8a4c4318..8291c8a9c 100644 --- a/app/services/message_templates/hook_execution_service.rb +++ b/app/services/message_templates/hook_execution_service.rb @@ -17,7 +17,7 @@ class MessageTemplates::HookExecutionService ::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? - ::MessageTemplates::Template::CsatSurvey.new(conversation: conversation).perform if should_send_csat_survey? + handle_csat_survey end def should_send_out_of_office_message? @@ -65,13 +65,26 @@ class MessageTemplates::HookExecutionService true end - def should_send_csat_survey? + def handle_csat_survey return unless csat_enabled_conversation? - # only send CSAT once in a conversation - return if conversation.messages.where(content_type: :input_csat).present? + return if csat_already_sent? - true + # Only send CSAT if agent can still reply by checking the messaging window restriction + # https://www.chatwoot.com/docs/self-hosted/supported-features#outgoing-message-restriction + if within_messaging_window? + ::MessageTemplates::Template::CsatSurvey.new(conversation: conversation).perform + else + conversation.create_csat_not_sent_activity_message + end + end + + def csat_already_sent? + conversation.messages.where(content_type: :input_csat).present? + end + + def within_messaging_window? + conversation.can_reply? end end MessageTemplates::HookExecutionService.prepend_mod_with('MessageTemplates::HookExecutionService') diff --git a/config/locales/en.yml b/config/locales/en.yml index 9a35197ad..b309e718c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -185,6 +185,8 @@ en: removed: '%{user_name} removed %{labels}' sla: added: '%{user_name} added SLA policy %{sla_name}' + csat: + not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions' removed: '%{user_name} removed SLA policy %{sla_name}' muted: '%{user_name} has muted the conversation' unmuted: '%{user_name} has unmuted the conversation' diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb index aef91603d..ad3446a13 100644 --- a/spec/models/conversation_spec.rb +++ b/spec/models/conversation_spec.rb @@ -435,6 +435,20 @@ RSpec.describe Conversation do end end + describe '#create_csat_not_sent_activity_message' do + subject(:create_csat_not_sent_activity_message) { conversation.create_csat_not_sent_activity_message } + + let(:conversation) { create(:conversation) } + + it 'creates CSAT not sent activity message' do + create_csat_not_sent_activity_message + expect(Conversations::ActivityMessageJob) + .to(have_been_enqueued.at_least(:once).with(conversation, { account_id: conversation.account_id, inbox_id: conversation.inbox_id, + message_type: :activity, + content: 'CSAT survey not sent due to outgoing message restrictions' })) + end + end + describe 'unread_messages' do subject(:unread_messages) { conversation.unread_messages } diff --git a/spec/services/message_templates/hook_execution_service_spec.rb b/spec/services/message_templates/hook_execution_service_spec.rb index 24e40ea8d..6e97aac42 100644 --- a/spec/services/message_templates/hook_execution_service_spec.rb +++ b/spec/services/message_templates/hook_execution_service_spec.rb @@ -121,8 +121,9 @@ describe MessageTemplates::HookExecutionService do create(:message, conversation: conversation, message_type: 'incoming') end - it 'calls ::MessageTemplates::Template::CsatSurvey when a conversation is resolved in an inbox with survey enabled' do + it 'calls ::MessageTemplates::Template::CsatSurvey when a conversation is resolved in an inbox with survey enabled and can reply' do conversation.inbox.update(csat_survey_enabled: true) + allow(conversation).to receive(:can_reply?).and_return(true) conversation.resolved! Conversations::ActivityMessageJob.perform_now(conversation, @@ -172,6 +173,32 @@ describe MessageTemplates::HookExecutionService do expect(MessageTemplates::Template::CsatSurvey).not_to have_received(:new).with(conversation: conversation) expect(csat_survey).not_to have_received(:perform) end + + it 'will not call ::MessageTemplates::Template::CsatSurvey if cannot reply' do + conversation.inbox.update(csat_survey_enabled: true) + allow(conversation).to receive(:can_reply?).and_return(false) + + conversation.resolved! + Conversations::ActivityMessageJob.perform_now(conversation, + { account_id: conversation.account_id, inbox_id: conversation.inbox_id, message_type: :activity, + content: 'Conversation marked resolved!!' }) + + expect(MessageTemplates::Template::CsatSurvey).not_to have_received(:new).with(conversation: conversation) + expect(csat_survey).not_to have_received(:perform) + end + + it 'creates activity message when CSAT not sent due to messaging window restriction' do + conversation.inbox.update(csat_survey_enabled: true) + allow(conversation).to receive(:can_reply?).and_return(false) + allow(conversation).to receive(:create_csat_not_sent_activity_message) + + conversation.resolved! + Conversations::ActivityMessageJob.perform_now(conversation, + { account_id: conversation.account_id, inbox_id: conversation.inbox_id, message_type: :activity, + content: 'Conversation marked resolved!!' }) + + expect(conversation).to have_received(:create_csat_not_sent_activity_message) + end end context 'when it is after working hours' do