fix: captain template message conflict (#13048)
Co-authored-by: aakashb95 <aakash@chatwoot.com> Co-authored-by: Shivam Mishra <scm.mymail@gmail.com> Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com>
This commit is contained in:
@@ -1,6 +1,14 @@
|
|||||||
class MessageTemplates::Template::OutOfOffice
|
class MessageTemplates::Template::OutOfOffice
|
||||||
pattr_initialize [:conversation!]
|
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
|
def perform
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
conversation.messages.create!(out_of_office_message_params)
|
conversation.messages.create!(out_of_office_message_params)
|
||||||
|
|||||||
@@ -87,10 +87,15 @@ class Captain::Conversation::ResponseBuilderJob < ApplicationJob
|
|||||||
I18n.with_locale(@assistant.account.locale) do
|
I18n.with_locale(@assistant.account.locale) do
|
||||||
create_handoff_message
|
create_handoff_message
|
||||||
@conversation.bot_handoff!
|
@conversation.bot_handoff!
|
||||||
|
send_out_of_office_message_if_applicable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def send_out_of_office_message_if_applicable
|
||||||
|
::MessageTemplates::Template::OutOfOffice.perform_if_applicable(@conversation)
|
||||||
|
end
|
||||||
|
|
||||||
def create_handoff_message
|
def create_handoff_message
|
||||||
create_outgoing_message(
|
create_outgoing_message(
|
||||||
@assistant.config['handoff_message'].presence || I18n.t('conversations.captain.handoff')
|
@assistant.config['handoff_message'].presence || I18n.t('conversations.captain.handoff')
|
||||||
|
|||||||
@@ -9,6 +9,24 @@ module Enterprise::MessageTemplates::HookExecutionService
|
|||||||
schedule_captain_response
|
schedule_captain_response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def should_send_greeting?
|
||||||
|
return false if captain_handling_conversation?
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_send_out_of_office_message?
|
||||||
|
return false if captain_handling_conversation?
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_send_email_collect?
|
||||||
|
return false if captain_handling_conversation?
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def schedule_captain_response
|
def schedule_captain_response
|
||||||
@@ -46,5 +64,14 @@ module Enterprise::MessageTemplates::HookExecutionService
|
|||||||
content: 'Transferring to another agent for further assistance.'
|
content: 'Transferring to another agent for further assistance.'
|
||||||
)
|
)
|
||||||
conversation.bot_handoff!
|
conversation.bot_handoff!
|
||||||
|
send_out_of_office_message_after_handoff
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_out_of_office_message_after_handoff
|
||||||
|
::MessageTemplates::Template::OutOfOffice.perform_if_applicable(conversation)
|
||||||
|
end
|
||||||
|
|
||||||
|
def captain_handling_conversation?
|
||||||
|
conversation.pending? && inbox.respond_to?(:captain_assistant) && inbox.captain_assistant.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ class Captain::Tools::HandoffTool < Captain::Tools::BasePublicTool
|
|||||||
|
|
||||||
# Trigger the bot handoff (sets status to open + dispatches events)
|
# Trigger the bot handoff (sets status to open + dispatches events)
|
||||||
conversation.bot_handoff!
|
conversation.bot_handoff!
|
||||||
|
|
||||||
|
# Send out of office message if applicable (since template messages were suppressed while Captain was handling)
|
||||||
|
send_out_of_office_message_if_applicable(conversation)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_out_of_office_message_if_applicable(conversation)
|
||||||
|
::MessageTemplates::Template::OutOfOffice.perform_if_applicable(conversation)
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: Future enhancement - Add team assignment capability
|
# TODO: Future enhancement - Add team assignment capability
|
||||||
|
|||||||
@@ -229,4 +229,106 @@ RSpec.describe Captain::Conversation::ResponseBuilderJob, type: :job do
|
|||||||
expect(described_class::MAX_MESSAGE_LENGTH).to eq(10_000)
|
expect(described_class::MAX_MESSAGE_LENGTH).to eq(10_000)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'out of office message after handoff' do
|
||||||
|
let(:conversation) { create(:conversation, inbox: inbox, account: account, status: :pending) }
|
||||||
|
let(:mock_llm_chat_service) { instance_double(Captain::Llm::AssistantChatService) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:message, conversation: conversation, content: 'Hello', message_type: :incoming)
|
||||||
|
allow(Captain::Llm::AssistantChatService).to receive(:new).and_return(mock_llm_chat_service)
|
||||||
|
allow(account).to receive(:feature_enabled?).and_return(false)
|
||||||
|
allow(account).to receive(:feature_enabled?).with('captain_integration_v2').and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when handoff occurs outside business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed. Please leave your email.'
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
allow(mock_llm_chat_service).to receive(:generate_response).and_return({ 'response' => 'conversation_handoff' })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends out of office message after handoff' do
|
||||||
|
expect do
|
||||||
|
described_class.perform_now(conversation, assistant)
|
||||||
|
end.to change { conversation.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
ooo_message = conversation.messages.template.last
|
||||||
|
expect(ooo_message.content).to eq('We are currently closed. Please leave your email.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when handoff occurs within business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed.'
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
open_all_day: true,
|
||||||
|
closed_all_day: false
|
||||||
|
)
|
||||||
|
allow(mock_llm_chat_service).to receive(:generate_response).and_return({ 'response' => 'conversation_handoff' })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not send out of office message after handoff' do
|
||||||
|
expect do
|
||||||
|
described_class.perform_now(conversation, assistant)
|
||||||
|
end.not_to(change { conversation.messages.template.count })
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when handoff occurs due to error outside business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed.'
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
allow(mock_llm_chat_service).to receive(:generate_response).and_raise(StandardError, 'API error')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends out of office message after error-triggered handoff' do
|
||||||
|
expect do
|
||||||
|
described_class.perform_now(conversation, assistant)
|
||||||
|
end.to change { conversation.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
ooo_message = conversation.messages.template.last
|
||||||
|
expect(ooo_message.content).to eq('We are currently closed.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no out of office message is configured' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: nil
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
allow(mock_llm_chat_service).to receive(:generate_response).and_return({ 'response' => 'conversation_handoff' })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not send out of office message' do
|
||||||
|
expect do
|
||||||
|
described_class.perform_now(conversation, assistant)
|
||||||
|
end.not_to(change { conversation.messages.template.count })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -163,4 +163,66 @@ RSpec.describe Captain::Tools::HandoffTool, type: :model do
|
|||||||
expect(tool.active?).to be true
|
expect(tool.active?).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'out of office message after handoff' do
|
||||||
|
context 'when outside business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed. Please leave your email.'
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends out of office message after handoff' do
|
||||||
|
expect do
|
||||||
|
tool.perform(tool_context, reason: 'Customer needs help')
|
||||||
|
end.to change { conversation.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
ooo_message = conversation.messages.template.last
|
||||||
|
expect(ooo_message.content).to eq('We are currently closed. Please leave your email.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when within business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed.'
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
open_all_day: true,
|
||||||
|
closed_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not send out of office message after handoff' do
|
||||||
|
expect do
|
||||||
|
tool.perform(tool_context, reason: 'Customer needs help')
|
||||||
|
end.not_to(change { conversation.messages.template.count })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no out of office message is configured' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: nil
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not send out of office message' do
|
||||||
|
expect do
|
||||||
|
tool.perform(tool_context, reason: 'Customer needs help')
|
||||||
|
end.not_to(change { conversation.messages.template.count })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,295 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe MessageTemplates::HookExecutionService do
|
||||||
|
let(:account) { create(:account, custom_attributes: { plan_name: 'startups' }) }
|
||||||
|
let(:inbox) { create(:inbox, account: account) }
|
||||||
|
let(:contact) { create(:contact, account: account) }
|
||||||
|
let(:conversation) { create(:conversation, inbox: inbox, account: account, contact: contact, status: :pending) }
|
||||||
|
let(:assistant) { create(:captain_assistant, account: account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:captain_inbox, captain_assistant: assistant, inbox: inbox)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when captain assistant is configured' do
|
||||||
|
context 'when within business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(working_hours_enabled: true)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
open_all_day: true,
|
||||||
|
closed_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'schedules captain response job for incoming messages on pending conversations' do
|
||||||
|
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when outside business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed'
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'schedules captain response job outside business hours (Captain always responds when configured)' do
|
||||||
|
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'performs captain handoff when quota is exceeded (OOO template will kick in after handoff)' do
|
||||||
|
account.update!(
|
||||||
|
limits: { 'captain_responses' => 100 },
|
||||||
|
custom_attributes: account.custom_attributes.merge('captain_responses_usage' => 100)
|
||||||
|
)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not send out of office message when Captain is handling' do
|
||||||
|
out_of_office_service = instance_double(MessageTemplates::Template::OutOfOffice)
|
||||||
|
allow(MessageTemplates::Template::OutOfOffice).to receive(:new).and_return(out_of_office_service)
|
||||||
|
allow(out_of_office_service).to receive(:perform).and_return(true)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
|
||||||
|
expect(MessageTemplates::Template::OutOfOffice).not_to have_received(:new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when business hours are not enabled' do
|
||||||
|
before do
|
||||||
|
inbox.update!(working_hours_enabled: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'schedules captain response job regardless of time' do
|
||||||
|
expect(Captain::Conversation::ResponseBuilderJob).to receive(:perform_later).with(conversation, assistant)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when captain quota is exceeded within business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(working_hours_enabled: true)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
open_all_day: true,
|
||||||
|
closed_all_day: false
|
||||||
|
)
|
||||||
|
|
||||||
|
account.update!(
|
||||||
|
limits: { 'captain_responses' => 100 },
|
||||||
|
custom_attributes: account.custom_attributes.merge('captain_responses_usage' => 100)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'performs handoff within business hours when quota exceeded' do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no captain assistant is configured' do
|
||||||
|
before do
|
||||||
|
CaptainInbox.where(inbox: inbox).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not schedule captain response job' do
|
||||||
|
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when conversation is not pending' do
|
||||||
|
before do
|
||||||
|
conversation.update!(status: :open)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not schedule captain response job' do
|
||||||
|
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when message is outgoing' do
|
||||||
|
it 'does not schedule captain response job' do
|
||||||
|
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
|
||||||
|
|
||||||
|
create(:message, conversation: conversation, message_type: :outgoing)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when greeting and out of office messages with Captain enabled' do
|
||||||
|
context 'when conversation is pending (Captain is handling)' do
|
||||||
|
before do
|
||||||
|
conversation.update!(status: :pending)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create greeting message in conversation' do
|
||||||
|
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.not_to(change { conversation.reload.messages.template.count })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create out of office message in conversation' do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed',
|
||||||
|
enable_email_collect: false
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.not_to(change { conversation.reload.messages.template.count })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when conversation is open (transferred to agent)' do
|
||||||
|
before do
|
||||||
|
conversation.update!(status: :open)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates greeting message in conversation' do
|
||||||
|
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
greeting_message = conversation.reload.messages.template.last
|
||||||
|
expect(greeting_message.content).to eq('Hello! How can we help you?')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates out of office message when outside business hours' do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed',
|
||||||
|
enable_email_collect: false
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
out_of_office_message = conversation.reload.messages.template.last
|
||||||
|
expect(out_of_office_message.content).to eq('We are currently closed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when Captain is not configured' do
|
||||||
|
before do
|
||||||
|
CaptainInbox.where(inbox: inbox).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates greeting message in conversation' do
|
||||||
|
inbox.update!(greeting_enabled: true, greeting_message: 'Hello! How can we help you?', enable_email_collect: false)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
greeting_message = conversation.reload.messages.template.last
|
||||||
|
expect(greeting_message.content).to eq('Hello! How can we help you?')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates out of office message when outside business hours' do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed',
|
||||||
|
enable_email_collect: false
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.to change { conversation.reload.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
out_of_office_message = conversation.reload.messages.template.last
|
||||||
|
expect(out_of_office_message.content).to eq('We are currently closed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when Captain quota is exceeded and handoff happens' do
|
||||||
|
before do
|
||||||
|
account.update!(
|
||||||
|
limits: { 'captain_responses' => 100 },
|
||||||
|
custom_attributes: account.custom_attributes.merge('captain_responses_usage' => 100)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when outside business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed. Please leave your email.',
|
||||||
|
enable_email_collect: false
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
closed_all_day: true,
|
||||||
|
open_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends out of office message after handoff due to quota exceeded' do
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.to change { conversation.messages.template.count }.by(1)
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
ooo_message = conversation.messages.template.last
|
||||||
|
expect(ooo_message.content).to eq('We are currently closed. Please leave your email.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when within business hours' do
|
||||||
|
before do
|
||||||
|
inbox.update!(
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message: 'We are currently closed.',
|
||||||
|
enable_email_collect: false
|
||||||
|
)
|
||||||
|
inbox.working_hours.find_by(day_of_week: Time.current.in_time_zone(inbox.timezone).wday).update!(
|
||||||
|
open_all_day: true,
|
||||||
|
closed_all_day: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not send out of office message after handoff' do
|
||||||
|
expect do
|
||||||
|
create(:message, conversation: conversation, message_type: :incoming)
|
||||||
|
end.not_to(change { conversation.messages.template.count })
|
||||||
|
|
||||||
|
expect(conversation.reload.status).to eq('open')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user