Improved sla calculation. Added Unit Tests.
This commit is contained in:
parent
dc060a28c2
commit
315a936bd4
3 changed files with 233 additions and 56 deletions
|
@ -473,25 +473,13 @@ class Ticket < ApplicationModel
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def escalation_calculation
|
def _escalation_calculation_get_sla
|
||||||
|
|
||||||
# set escalation off if ticket is already closed
|
|
||||||
ticket_state = Ticket::State.lookup( :id => self.ticket_state_id )
|
|
||||||
ticket_state_type = Ticket::StateType.lookup( :id => ticket_state.state_type_id )
|
|
||||||
ignore_escalation = ['removed', 'closed', 'merged', 'pending action']
|
|
||||||
if ignore_escalation.include?(ticket_state_type.name)
|
|
||||||
self.escalation_time = nil
|
|
||||||
# self.first_response_escal_date = nil
|
|
||||||
# self.close_time_escal_date = nil
|
|
||||||
self.save
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
# get sla
|
|
||||||
sla_selected = nil
|
sla_selected = nil
|
||||||
Sla.where( :active => true ).each {|sla|
|
Sla.where( :active => true ).each {|sla|
|
||||||
if sla.condition
|
if !sla.condition || sla.condition.empty?
|
||||||
puts sla.condition.inspect
|
sla_selected = sla
|
||||||
|
elsif sla.condition
|
||||||
hit = false
|
hit = false
|
||||||
map = [
|
map = [
|
||||||
[ 'tickets.ticket_priority_id', 'ticket_priority_id' ],
|
[ 'tickets.ticket_priority_id', 'ticket_priority_id' ],
|
||||||
|
@ -515,16 +503,8 @@ class Ticket < ApplicationModel
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
# reset escalation if no sla is set
|
# get and set calendar settings
|
||||||
if !sla_selected
|
if sla_selected
|
||||||
self.escalation_time = nil
|
|
||||||
# self.first_response_escal_date = nil
|
|
||||||
# self.close_time_escal_date = nil
|
|
||||||
self.save
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
# get calendar settings
|
|
||||||
BusinessTime::Config.beginning_of_workday = sla_selected.data['beginning_of_workday']
|
BusinessTime::Config.beginning_of_workday = sla_selected.data['beginning_of_workday']
|
||||||
BusinessTime::Config.end_of_workday = sla_selected.data['end_of_workday']
|
BusinessTime::Config.end_of_workday = sla_selected.data['end_of_workday']
|
||||||
days = []
|
days = []
|
||||||
|
@ -534,65 +514,122 @@ class Ticket < ApplicationModel
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
BusinessTime::Config.work_week = days
|
BusinessTime::Config.work_week = days
|
||||||
|
end
|
||||||
|
return sla_selected
|
||||||
|
end
|
||||||
|
|
||||||
|
def _escalation_calculation_dest_time(start_time, diff_min)
|
||||||
|
start_time = Time.parse( start_time.to_s )
|
||||||
|
dest_time = (diff_min / 60).round.business_hour.after( start_time )
|
||||||
|
return dest_time
|
||||||
|
end
|
||||||
|
|
||||||
|
def _escalation_calculation_higher_time(escalation_time, check_time, done_time)
|
||||||
|
return escalation_time if done_time
|
||||||
|
return check_time if !escalation_time
|
||||||
|
return escalation_time if !check_time
|
||||||
|
return check_time if escalation_time > check_time
|
||||||
|
return escalation_time
|
||||||
|
end
|
||||||
|
|
||||||
|
def _escalation_calculation_business_time_diff(start_time, end_time)
|
||||||
|
start_time = Time.parse(start_time.to_s)
|
||||||
|
end_time = Time.parse(end_time.to_s)
|
||||||
|
diff = start_time.business_time_until(end_time) / 60
|
||||||
|
diff.round
|
||||||
|
end
|
||||||
|
|
||||||
|
def escalation_calculation
|
||||||
|
|
||||||
|
# set escalation off if ticket is already closed
|
||||||
|
ticket_state = Ticket::State.lookup( :id => self.ticket_state_id )
|
||||||
|
ticket_state_type = Ticket::StateType.lookup( :id => ticket_state.state_type_id )
|
||||||
|
ignore_escalation = ['removed', 'closed', 'merged', 'pending action']
|
||||||
|
if ignore_escalation.include?( ticket_state_type.name )
|
||||||
|
self.escalation_time = nil
|
||||||
|
# self.first_response_escal_date = nil
|
||||||
|
# self.close_time_escal_date = nil
|
||||||
|
self.save
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
# get sla for ticket
|
||||||
|
sla_selected = self._escalation_calculation_get_sla
|
||||||
|
|
||||||
|
# reset escalation if no sla is set
|
||||||
|
if !sla_selected
|
||||||
|
self.escalation_time = nil
|
||||||
|
# self.first_response_escal_date = nil
|
||||||
|
# self.close_time_escal_date = nil
|
||||||
|
self.save
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
# puts sla_selected.inspect
|
# puts sla_selected.inspect
|
||||||
# puts days.inspect
|
# puts days.inspect
|
||||||
|
|
||||||
self.escalation_time = nil
|
self.escalation_time = nil
|
||||||
self.first_response_escal_date = nil
|
self.first_response_escal_date = nil
|
||||||
|
self.update_time_escal_date = nil
|
||||||
self.close_time_escal_date = nil
|
self.close_time_escal_date = nil
|
||||||
|
|
||||||
# first response
|
# first response
|
||||||
if sla_selected.first_response_time
|
if sla_selected.first_response_time
|
||||||
created_at = Time.parse(self.created_at.to_s)
|
self.first_response_escal_date = self._escalation_calculation_dest_time( created_at, sla_selected.first_response_time )
|
||||||
self.first_response_escal_date = (sla_selected.first_response_time / 60).round.business_hour.after( created_at )
|
|
||||||
|
|
||||||
# set ticket escalation
|
# set ticket escalation
|
||||||
if !self.first_response && (!self.escalation_time || self.escalation_time > self.first_response_escal_date)
|
self.escalation_time = self._escalation_calculation_higher_time( self.escalation_time, self.first_response_escal_date, self.first_response )
|
||||||
self.escalation_time = self.first_response_escal_date
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
if self.first_response# && !self.first_response_in_min
|
||||||
|
# created_at = Time.parse(self.created_at.to_s)
|
||||||
|
# first_response_at = Time.parse(self.first_response.to_s)
|
||||||
|
# diff = created_at.business_time_until(first_response_at) / 60
|
||||||
|
# self.first_response_in_min = diff.round
|
||||||
|
self.first_response_in_min = self._escalation_calculation_business_time_diff( self.created_at, self.first_response )
|
||||||
|
|
||||||
if self.first_response && !self.first_response_in_min
|
|
||||||
created_at = Time.parse(self.created_at.to_s)
|
|
||||||
first_response_at = Time.parse(self.first_response.to_s)
|
|
||||||
diff = created_at.business_time_until(first_response_at) / 60
|
|
||||||
self.first_response_in_min = diff.round
|
|
||||||
end
|
end
|
||||||
|
# set sla time
|
||||||
# set time over sla
|
|
||||||
if sla_selected.first_response_time && self.first_response_in_min
|
if sla_selected.first_response_time && self.first_response_in_min
|
||||||
self.first_response_diff_in_min = sla_selected.first_response_time - self.first_response_in_min
|
self.first_response_diff_in_min = sla_selected.first_response_time - self.first_response_in_min
|
||||||
end
|
end
|
||||||
|
|
||||||
# # update time
|
# update time
|
||||||
# if sla_selected.close_time
|
if sla_selected.update_time
|
||||||
|
last_update = self.last_contact_agent
|
||||||
|
if !last_update
|
||||||
|
last_update = self.created_at
|
||||||
|
end
|
||||||
|
self.update_time_escal_date = self._escalation_calculation_dest_time( last_update, sla_selected.update_time )
|
||||||
|
|
||||||
|
# set ticket escalation
|
||||||
|
self.escalation_time = self._escalation_calculation_higher_time( self.escalation_time, self.update_time_escal_date, false )
|
||||||
|
end
|
||||||
|
|
||||||
|
# if self.last_contact_agent && !self.update_time_in_min
|
||||||
# created_at = Time.parse(self.created_at.to_s)
|
# created_at = Time.parse(self.created_at.to_s)
|
||||||
# self.close_time_escal_date = (sla_selected.close_time / 60).round.business_hour.after( created_at )
|
# last_contact_agent = Time.parse(self.last_contact_agent.to_s)
|
||||||
|
# diff = created_at.business_time_until(closed_at) / 60
|
||||||
|
# self.close_time_in_min = diff.round
|
||||||
# end
|
# end
|
||||||
|
|
||||||
# close time
|
# close time
|
||||||
if sla_selected.close_time
|
if sla_selected.close_time
|
||||||
created_at = Time.parse(self.created_at.to_s)
|
self.close_time_escal_date = self._escalation_calculation_dest_time( self.created_at, sla_selected.close_time )
|
||||||
self.close_time_escal_date = (sla_selected.close_time / 60).round.business_hour.after( created_at )
|
|
||||||
|
|
||||||
# set ticket escalation
|
# set ticket escalation
|
||||||
if !self.close_time && (!self.escalation_time || self.escalation_time > self.close_time_escal_date)
|
self.escalation_time = self._escalation_calculation_higher_time( self.escalation_time, self.close_time_escal_date, self.close_time )
|
||||||
self.escalation_time = self.close_time_escal_date
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
if self.close_time# && !self.close_time_in_min
|
||||||
|
# created_at = Time.parse(self.created_at.to_s)
|
||||||
|
# closed_at = Time.parse(self.close_time.to_s)
|
||||||
|
# diff = created_at.business_time_until(closed_at) / 60
|
||||||
|
# self.close_time_in_min = diff.round
|
||||||
|
self.close_time_in_min = self._escalation_calculation_business_time_diff( self.created_at, self.close_time )
|
||||||
|
|
||||||
if self.close_time && !self.close_time_in_min
|
|
||||||
created_at = Time.parse(self.created_at.to_s)
|
|
||||||
closed_at = Time.parse(self.close_time.to_s)
|
|
||||||
diff = created_at.business_time_until(closed_at) / 60
|
|
||||||
self.close_time_in_min = diff.round
|
|
||||||
end
|
end
|
||||||
|
# set sla time
|
||||||
# set time over sla
|
|
||||||
if sla_selected.close_time && self.close_time_in_min
|
if sla_selected.close_time && self.close_time_in_min
|
||||||
self.close_time_diff_in_min = sla_selected.close_time - self.close_time_in_min
|
self.close_time_diff_in_min = sla_selected.close_time - self.close_time_in_min
|
||||||
end
|
end
|
||||||
|
|
||||||
self.save
|
self.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
13
db/migrate/20130321124312_ticket_escalation_update_time.rb
Normal file
13
db/migrate/20130321124312_ticket_escalation_update_time.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
class TicketEscalationUpdateTime < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
add_column :tickets, :update_time_escal_date, :timestamp, :null => true
|
||||||
|
add_column :tickets, :updtate_time_sla_time, :timestamp, :null => true
|
||||||
|
add_column :tickets, :update_time_in_min, :integer, :null => true
|
||||||
|
add_column :tickets, :update_time_diff_in_min, :integer, :null => true
|
||||||
|
add_index :tickets, [:update_time_in_min]
|
||||||
|
add_index :tickets, [:update_time_diff_in_min]
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
end
|
||||||
|
end
|
127
test/unit/ticket_test.rb
Normal file
127
test/unit/ticket_test.rb
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class TicketTest < ActiveSupport::TestCase
|
||||||
|
test 'ticket create' do
|
||||||
|
ticket = Ticket.create(
|
||||||
|
:title => 'some title äöüß',
|
||||||
|
:group => Group.lookup( :name => 'Users'),
|
||||||
|
:customer_id => 2,
|
||||||
|
:ticket_state => Ticket::State.lookup( :name => 'new' ),
|
||||||
|
:ticket_priority => Ticket::Priority.lookup( :name => '2 normal' ),
|
||||||
|
:updated_by_id => 1,
|
||||||
|
:created_by_id => 1,
|
||||||
|
)
|
||||||
|
assert( ticket, "ticket created" )
|
||||||
|
|
||||||
|
assert_equal( ticket.title, 'some title äöüß', 'ticket.title verify' )
|
||||||
|
assert_equal( ticket.group.name, 'Users', 'ticket.group verify' )
|
||||||
|
assert_equal( ticket.ticket_state.name, 'new', 'ticket.state verify' )
|
||||||
|
|
||||||
|
delete = ticket.destroy
|
||||||
|
assert( delete, "ticket destroy" )
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'ticket sla' do
|
||||||
|
ticket = Ticket.create(
|
||||||
|
:title => 'some title äöüß',
|
||||||
|
:group => Group.lookup( :name => 'Users'),
|
||||||
|
:customer_id => 2,
|
||||||
|
:ticket_state => Ticket::State.lookup( :name => 'new' ),
|
||||||
|
:ticket_priority => Ticket::Priority.lookup( :name => '2 normal' ),
|
||||||
|
:created_at => '2013-03-21 09:30:00 UTC',
|
||||||
|
:updated_at => '2013-03-21 09:30:00 UTC',
|
||||||
|
:updated_by_id => 1,
|
||||||
|
:created_by_id => 1,
|
||||||
|
)
|
||||||
|
assert( ticket, "ticket created" )
|
||||||
|
assert_equal( ticket.escalation_time, nil, 'ticket.escalation_time verify' )
|
||||||
|
|
||||||
|
sla = Sla.create(
|
||||||
|
:name => 'test sla 1',
|
||||||
|
:condition => {},
|
||||||
|
:data => {
|
||||||
|
"Mon"=>"Mon", "Tue"=>"Tue", "Wed"=>"Wed", "Thu"=>"Thu", "Fri"=>"Fri", "Sat"=>"Sat", "Sun"=>"Sun",
|
||||||
|
"beginning_of_workday" => "8:00",
|
||||||
|
"end_of_workday" => "18:00",
|
||||||
|
},
|
||||||
|
:first_response_time => 120,
|
||||||
|
:update_time => 180,
|
||||||
|
:close_time => 240,
|
||||||
|
:active => true,
|
||||||
|
:updated_by_id => 1,
|
||||||
|
:created_by_id => 1,
|
||||||
|
)
|
||||||
|
ticket = Ticket.find(ticket.id)
|
||||||
|
assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.escalation_time verify 1' )
|
||||||
|
assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.first_response_escal_date verify 1' )
|
||||||
|
assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.update_time_escal_date verify 1' )
|
||||||
|
assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 13:30:00 UTC', 'ticket.close_time_escal_date verify 1' )
|
||||||
|
delete = sla.destroy
|
||||||
|
assert( delete, "sla destroy 1" )
|
||||||
|
|
||||||
|
sla = Sla.create(
|
||||||
|
:name => 'test sla 2',
|
||||||
|
:condition => { "tickets.ticket_priority_id" =>["1", "2", "3"] },
|
||||||
|
:data => {
|
||||||
|
"Mon"=>"Mon", "Tue"=>"Tue", "Wed"=>"Wed", "Thu"=>"Thu", "Fri"=>"Fri", "Sat"=>"Sat", "Sun"=>"Sun",
|
||||||
|
"beginning_of_workday" => "8:00",
|
||||||
|
"end_of_workday" => "18:00",
|
||||||
|
},
|
||||||
|
:first_response_time => 60,
|
||||||
|
:update_time => 120,
|
||||||
|
:close_time => 180,
|
||||||
|
:active => true,
|
||||||
|
:updated_by_id => 1,
|
||||||
|
:created_by_id => 1,
|
||||||
|
)
|
||||||
|
ticket = Ticket.find(ticket.id)
|
||||||
|
assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 10:30:00 UTC', 'ticket.escalation_time verify 2' )
|
||||||
|
assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 10:30:00 UTC', 'ticket.first_response_escal_date verify 2' )
|
||||||
|
assert_equal( ticket.first_response, nil, 'ticket.first_response verify 2' )
|
||||||
|
assert_equal( ticket.first_response_in_min, nil, 'ticket.first_response_in_min verify 2' )
|
||||||
|
assert_equal( ticket.first_response_diff_in_min, nil, 'ticket.first_response_diff_in_min verify 2' )
|
||||||
|
assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.update_time_escal_date verify 2' )
|
||||||
|
assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.close_time_escal_date verify 2' )
|
||||||
|
|
||||||
|
ticket.update_attributes(
|
||||||
|
# :first_response_escal_date => '2013-03-26 09:30:00 UTC',
|
||||||
|
:first_response => '2013-03-21 10:00:00 UTC',
|
||||||
|
)
|
||||||
|
ticket.escalation_calculation
|
||||||
|
puts ticket.inspect
|
||||||
|
|
||||||
|
assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.escalation_time verify 3' )
|
||||||
|
assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 10:30:00 UTC', 'ticket.first_response_escal_date verify 3' )
|
||||||
|
assert_equal( ticket.first_response.gmtime.to_s, '2013-03-21 10:00:00 UTC', 'ticket.first_response verify 3' )
|
||||||
|
assert_equal( ticket.first_response_in_min, 30, 'ticket.first_response_in_min verify 3' )
|
||||||
|
assert_equal( ticket.first_response_diff_in_min, 30, 'ticket.first_response_diff_in_min verify 3' )
|
||||||
|
assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.update_time_escal_date verify 3' )
|
||||||
|
assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.close_time_escal_date verify 3' )
|
||||||
|
|
||||||
|
ticket.update_attributes(
|
||||||
|
# :first_response_escal_date => '2013-03-26 09:30:00 UTC',
|
||||||
|
:first_response => '2013-03-21 14:00:00 UTC',
|
||||||
|
)
|
||||||
|
ticket.escalation_calculation
|
||||||
|
puts ticket.inspect
|
||||||
|
|
||||||
|
assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.escalation_time verify 4' )
|
||||||
|
assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 10:30:00 UTC', 'ticket.first_response_escal_date verify 4' )
|
||||||
|
assert_equal( ticket.first_response.gmtime.to_s, '2013-03-21 14:00:00 UTC', 'ticket.first_response verify 4' )
|
||||||
|
assert_equal( ticket.first_response_in_min, 270, 'ticket.first_response_in_min verify 4' )
|
||||||
|
assert_equal( ticket.first_response_diff_in_min, -210, 'ticket.first_response_diff_in_min verify 4' )
|
||||||
|
assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.update_time_escal_date verify 4' )
|
||||||
|
assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.close_time_escal_date verify 4' )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
delete = sla.destroy
|
||||||
|
assert( delete, "sla destroy 2" )
|
||||||
|
|
||||||
|
delete = ticket.destroy
|
||||||
|
assert( delete, "ticket destroy" )
|
||||||
|
delete = sla.destroy
|
||||||
|
assert( delete, "sla destroy" )
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue