Implemented #1865 - Date of last contact (customer) - make behaviour configurable.
This commit is contained in:
parent
b403432c76
commit
8f708b75ea
4 changed files with 181 additions and 40 deletions
|
@ -110,6 +110,18 @@ class Observer::Ticket::ArticleChanges < ActiveRecord::Observer
|
||||||
ticket = record.ticket
|
ticket = record.ticket
|
||||||
if sender.name == 'Customer'
|
if sender.name == 'Customer'
|
||||||
|
|
||||||
|
# in case, update last_contact_customer_at on any customer follow up
|
||||||
|
if Setting.get('ticket_last_contact_behaviour') == 'based_on_customer_reaction'
|
||||||
|
|
||||||
|
# set last_contact_at customer
|
||||||
|
record.ticket.last_contact_customer_at = record.created_at
|
||||||
|
|
||||||
|
# set last_contact
|
||||||
|
record.ticket.last_contact_at = record.created_at
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
# if customer is sending agains, ignore update of last contact (usecase of update escalation)
|
# if customer is sending agains, ignore update of last contact (usecase of update escalation)
|
||||||
return false if ticket.last_contact_customer_at &&
|
return false if ticket.last_contact_customer_at &&
|
||||||
ticket.last_contact_at &&
|
ticket.last_contact_at &&
|
||||||
|
@ -125,7 +137,6 @@ class Observer::Ticket::ArticleChanges < ActiveRecord::Observer
|
||||||
|
|
||||||
# set last_contact
|
# set last_contact
|
||||||
record.ticket.last_contact_at = record.created_at
|
record.ticket.last_contact_at = record.created_at
|
||||||
|
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
33
db/migrate/20180521141004_ticket_last_contact_behavior.rb
Normal file
33
db/migrate/20180521141004_ticket_last_contact_behavior.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
class TicketLastContactBehavior < ActiveRecord::Migration[5.1]
|
||||||
|
def up
|
||||||
|
# return if it's a new setup
|
||||||
|
return if !Setting.find_by(name: 'system_init_done')
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Ticket Last Contact Behaviour',
|
||||||
|
name: 'ticket_last_contact_behaviour',
|
||||||
|
area: 'Ticket::Base',
|
||||||
|
description: 'Sets the last customer contact based on the last contact of a customer or on the last contact of a customer to whom an agent has not yet responded.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'ticket_last_contact_behaviour',
|
||||||
|
tag: 'select',
|
||||||
|
translate: true,
|
||||||
|
options: {
|
||||||
|
'based_on_customer_reaction' => 'Last customer contact (without consideration an agent has replied to it)',
|
||||||
|
'check_if_agent_already_replied' => 'Last customer contact (with consideration an agent has replied to it)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: 'check_if_agent_already_replied',
|
||||||
|
preferences: {
|
||||||
|
permission: ['admin.ticket'],
|
||||||
|
},
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1789,6 +1789,32 @@ Setting.create_if_not_exists(
|
||||||
},
|
},
|
||||||
frontend: false
|
frontend: false
|
||||||
)
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'Ticket Last Contact Behaviour',
|
||||||
|
name: 'ticket_last_contact_behaviour',
|
||||||
|
area: 'Ticket::Base',
|
||||||
|
description: 'Sets the last customer contact based on the last contact of a customer or on the last contact of a customer to whom an agent has not yet responded.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'ticket_last_contact_behaviour',
|
||||||
|
tag: 'select',
|
||||||
|
translate: true,
|
||||||
|
options: {
|
||||||
|
'based_on_customer_reaction' => 'Last customer contact (without consideration an agent has replied to it)',
|
||||||
|
'check_if_agent_already_replied' => 'Last customer contact (with consideration an agent has replied to it)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: 'check_if_agent_already_replied',
|
||||||
|
preferences: {
|
||||||
|
permission: ['admin.ticket'],
|
||||||
|
},
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
title: 'Ticket Number Format',
|
title: 'Ticket Number Format',
|
||||||
name: 'ticket_number',
|
name: 'ticket_number',
|
||||||
|
|
|
@ -4,11 +4,6 @@ require 'test_helper'
|
||||||
class TicketSlaTest < ActiveSupport::TestCase
|
class TicketSlaTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
test 'ticket sla' do
|
test 'ticket sla' do
|
||||||
|
|
||||||
# cleanup
|
|
||||||
delete = Ticket.destroy_all
|
|
||||||
assert(delete, 'ticket destroy_all')
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
ticket = Ticket.create!(
|
||||||
title: 'some title äöüß',
|
title: 'some title äöüß',
|
||||||
group: Group.lookup(name: 'Users'),
|
group: Group.lookup(name: 'Users'),
|
||||||
|
@ -502,11 +497,6 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'ticket sla + selector' do
|
test 'ticket sla + selector' do
|
||||||
|
|
||||||
# cleanup
|
|
||||||
delete = Ticket.destroy_all
|
|
||||||
assert(delete, 'ticket destroy_all')
|
|
||||||
|
|
||||||
calendar1 = Calendar.create_or_update(
|
calendar1 = Calendar.create_or_update(
|
||||||
name: 'EU 1',
|
name: 'EU 1',
|
||||||
timezone: 'Europe/Berlin',
|
timezone: 'Europe/Berlin',
|
||||||
|
@ -611,13 +601,6 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'ticket sla + timezone + holiday' do
|
test 'ticket sla + timezone + holiday' do
|
||||||
|
|
||||||
# cleanup
|
|
||||||
delete = Sla.destroy_all
|
|
||||||
assert(delete, 'sla destroy_all')
|
|
||||||
delete = Ticket.destroy_all
|
|
||||||
assert(delete, 'ticket destroy_all')
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
ticket = Ticket.create!(
|
||||||
title: 'some title äöüß',
|
title: 'some title äöüß',
|
||||||
group: Group.lookup(name: 'Users'),
|
group: Group.lookup(name: 'Users'),
|
||||||
|
@ -862,13 +845,6 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'ticket escalation suspend close reopen bug' do
|
test 'ticket escalation suspend close reopen bug' do
|
||||||
|
|
||||||
# cleanup
|
|
||||||
delete = Sla.destroy_all
|
|
||||||
assert(delete, 'sla destroy_all')
|
|
||||||
delete = Ticket.destroy_all
|
|
||||||
assert(delete, 'ticket destroy_all')
|
|
||||||
|
|
||||||
ticket1 = Ticket.create!(
|
ticket1 = Ticket.create!(
|
||||||
title: 'some title äöüß3',
|
title: 'some title äöüß3',
|
||||||
group: Group.lookup(name: 'Users'),
|
group: Group.lookup(name: 'Users'),
|
||||||
|
@ -1568,7 +1544,6 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'ticket ticket.title and article.subject' do
|
test 'ticket ticket.title and article.subject' do
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
ticket = Ticket.create!(
|
||||||
title: 'some title SLATEST1 for you',
|
title: 'some title SLATEST1 for you',
|
||||||
group: Group.lookup(name: 'Users'),
|
group: Group.lookup(name: 'Users'),
|
||||||
|
@ -1735,13 +1710,6 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'ticket sla + holiday 222' do
|
test 'ticket sla + holiday 222' do
|
||||||
|
|
||||||
# cleanup
|
|
||||||
delete = Sla.destroy_all
|
|
||||||
assert(delete, 'sla destroy_all')
|
|
||||||
delete = Ticket.destroy_all
|
|
||||||
assert(delete, 'ticket destroy_all')
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
ticket = Ticket.create!(
|
||||||
title: 'some title 222',
|
title: 'some title 222',
|
||||||
group: Group.lookup(name: 'Users'),
|
group: Group.lookup(name: 'Users'),
|
||||||
|
@ -1961,13 +1929,6 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'ticket sla + observer check' do
|
test 'ticket sla + observer check' do
|
||||||
|
|
||||||
# cleanup
|
|
||||||
delete = Sla.destroy_all
|
|
||||||
assert(delete, 'sla destroy_all')
|
|
||||||
delete = Ticket.destroy_all
|
|
||||||
assert(delete, 'ticket destroy_all')
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
ticket = Ticket.create!(
|
||||||
title: 'some title observer#1',
|
title: 'some title observer#1',
|
||||||
group: Group.lookup(name: 'Users'),
|
group: Group.lookup(name: 'Users'),
|
||||||
|
@ -2143,4 +2104,114 @@ class TicketSlaTest < ActiveSupport::TestCase
|
||||||
calendar.destroy!
|
calendar.destroy!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'update last_customer_contact_at when the agent does not reply' do
|
||||||
|
|
||||||
|
Setting.set('ticket_last_contact_behaviour', 'based_on_customer_reaction')
|
||||||
|
|
||||||
|
ticket = Ticket.create!(
|
||||||
|
title: 'test #1 last_contact_customer_at',
|
||||||
|
group: Group.lookup(name: 'Users'),
|
||||||
|
customer_id: 2,
|
||||||
|
state: Ticket::State.lookup(name: 'new'),
|
||||||
|
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||||
|
created_at: '2018-05-01 13:56:21 UTC',
|
||||||
|
updated_at: '2018-05-01 13:56:21 UTC',
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
assert(ticket, 'ticket created')
|
||||||
|
|
||||||
|
article1 = Ticket::Article.create!(
|
||||||
|
ticket_id: ticket.id,
|
||||||
|
from: 'some_sender@example.com',
|
||||||
|
subject: 'some subject',
|
||||||
|
message_id: 'some@id',
|
||||||
|
body: 'some message',
|
||||||
|
internal: false,
|
||||||
|
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||||
|
type: Ticket::Article::Type.where(name: 'phone').first,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
created_at: '2018-05-01 13:56:21 UTC',
|
||||||
|
updated_at: '2018-05-01 13:56:21 UTC',
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket.reload
|
||||||
|
assert_equal(ticket.article_count, 1)
|
||||||
|
assert_equal(ticket.last_contact_at.to_s, article1.created_at.to_s)
|
||||||
|
assert_equal(ticket.last_contact_customer_at.to_s, article1.created_at.to_s)
|
||||||
|
assert_nil(ticket.last_contact_agent_at)
|
||||||
|
assert_nil(ticket.first_response_at)
|
||||||
|
assert_nil(ticket.close_at)
|
||||||
|
|
||||||
|
article2 = Ticket::Article.create!(
|
||||||
|
ticket_id: ticket.id,
|
||||||
|
from: 'some_sender@example.com',
|
||||||
|
subject: 'some subject',
|
||||||
|
message_id: 'some@id',
|
||||||
|
body: 'some message',
|
||||||
|
internal: false,
|
||||||
|
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||||
|
type: Ticket::Article::Type.where(name: 'phone').first,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
created_at: '2018-05-01 14:56:21 UTC',
|
||||||
|
updated_at: '2018-05-01 14:56:21 UTC',
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket = Ticket.find(ticket.id)
|
||||||
|
assert_equal(ticket.article_count, 2)
|
||||||
|
assert_equal(ticket.last_contact_at.to_s, article2.created_at.to_s)
|
||||||
|
assert_equal(ticket.last_contact_customer_at.to_s, article2.created_at.to_s)
|
||||||
|
assert_nil(ticket.last_contact_agent_at)
|
||||||
|
assert_nil(ticket.first_response_at)
|
||||||
|
assert_nil(ticket.close_at)
|
||||||
|
|
||||||
|
article3 = Ticket::Article.create!(
|
||||||
|
ticket_id: ticket.id,
|
||||||
|
from: 'some_sender@example.com',
|
||||||
|
subject: 'some subject',
|
||||||
|
message_id: 'some@id',
|
||||||
|
body: 'some message',
|
||||||
|
internal: false,
|
||||||
|
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||||
|
type: Ticket::Article::Type.where(name: 'phone').first,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
created_at: '2018-05-01 15:56:21 UTC',
|
||||||
|
updated_at: '2018-05-01 15:56:21 UTC',
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket.reload
|
||||||
|
assert_equal(ticket.article_count, 3)
|
||||||
|
assert_equal(ticket.last_contact_at.to_s, article3.created_at.to_s)
|
||||||
|
assert_equal(ticket.last_contact_customer_at.to_s, article3.created_at.to_s)
|
||||||
|
assert_nil(ticket.last_contact_agent_at)
|
||||||
|
assert_nil(ticket.first_response_at)
|
||||||
|
assert_nil(ticket.close_at)
|
||||||
|
|
||||||
|
article4 = Ticket::Article.create!(
|
||||||
|
ticket_id: ticket.id,
|
||||||
|
from: 'some_sender@example.com',
|
||||||
|
subject: 'some subject',
|
||||||
|
message_id: 'some@id',
|
||||||
|
body: 'some message',
|
||||||
|
internal: false,
|
||||||
|
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||||
|
type: Ticket::Article::Type.where(name: 'phone').first,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
created_at: '2018-05-01 16:56:21 UTC',
|
||||||
|
updated_at: '2018-05-01 16:56:21 UTC',
|
||||||
|
)
|
||||||
|
|
||||||
|
ticket.reload
|
||||||
|
assert_equal(ticket.article_count, 4)
|
||||||
|
assert_equal(ticket.last_contact_at.to_s, article4.created_at.to_s)
|
||||||
|
assert_equal(ticket.last_contact_customer_at.to_s, article3.created_at.to_s)
|
||||||
|
assert_equal(ticket.last_contact_agent_at.to_s, article4.created_at.to_s)
|
||||||
|
assert_equal(ticket.first_response_at.to_s, article4.created_at.to_s)
|
||||||
|
assert_nil(ticket.close_at)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue