2013-06-12 15:59:58 +00:00
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
2013-03-25 12:42:42 +00:00
require 'time_calculation'
2013-04-30 12:13:53 +00:00
require 'sla'
2012-07-29 20:25:31 +00:00
class Ticket < ApplicationModel
2013-08-15 22:16:38 +00:00
before_create :check_generate , :check_defaults
2012-11-13 10:34:45 +00:00
before_update :check_defaults
2012-07-20 08:08:31 +00:00
before_destroy :destroy_dependencies
2013-06-29 00:13:03 +00:00
after_create :notify_clients_after_create
after_update :notify_clients_after_update
after_destroy :notify_clients_after_destroy
2013-01-01 20:29:26 +00:00
2012-04-16 08:04:49 +00:00
belongs_to :group
2012-12-24 13:55:43 +00:00
has_many :articles , :class_name = > 'Ticket::Article' , :after_add = > :cache_update , :after_remove = > :cache_update
2012-11-13 10:34:45 +00:00
belongs_to :organization
2012-12-24 13:55:43 +00:00
belongs_to :ticket_state , :class_name = > 'Ticket::State'
belongs_to :ticket_priority , :class_name = > 'Ticket::Priority'
belongs_to :owner , :class_name = > 'User'
belongs_to :customer , :class_name = > 'User'
belongs_to :created_by , :class_name = > 'User'
belongs_to :create_article_type , :class_name = > 'Ticket::Article::Type'
belongs_to :create_article_sender , :class_name = > 'Ticket::Article::Sender'
2012-04-10 14:06:46 +00:00
2013-03-28 23:13:15 +00:00
attr_accessor :callback_loop
2012-04-10 14:06:46 +00:00
def agent_of_group
2013-01-01 20:29:26 +00:00
Group . find ( self . group_id ) . users . where ( :active = > true ) . joins ( :roles ) . where ( 'roles.name' = > 'Agent' , 'roles.active' = > true ) . uniq ( )
2012-04-10 14:06:46 +00:00
end
def self . agents
User . where ( :active = > true ) . joins ( :roles ) . where ( 'roles.name' = > 'Agent' , 'roles.active' = > true ) . uniq ( )
end
2013-01-04 08:09:59 +00:00
def self . attributes_to_change ( params )
if params [ :ticket_id ]
params [ :ticket ] = self . find ( params [ :ticket_id ] )
end
if params [ :article_id ]
params [ :article ] = self . find ( params [ :article_id ] )
end
# get ticket states
ticket_state_ids = [ ]
if params [ :ticket ]
ticket_state_type = params [ :ticket ] . ticket_state . state_type
end
ticket_state_types = [ 'open' , 'closed' , 'pending action' , 'pending reminder' ]
if ticket_state_type && ! ticket_state_types . include? ( ticket_state_type . name )
ticket_state_ids . push params [ :ticket ] . ticket_state . id
end
ticket_state_types . each { | type |
ticket_state_type = Ticket :: StateType . where ( :name = > type ) . first
if ticket_state_type
ticket_state_type . states . each { | ticket_state |
ticket_state_ids . push ticket_state . id
}
end
}
# get owner
owner_ids = [ ]
if params [ :ticket ]
params [ :ticket ] . agent_of_group . each { | user |
owner_ids . push user . id
}
end
2013-06-12 15:59:58 +00:00
2013-01-04 08:09:59 +00:00
# get group
group_ids = [ ]
Group . where ( :active = > true ) . each { | group |
group_ids . push group . id
}
# get group / user relations
agents = { }
Ticket . agents . each { | user |
agents [ user . id ] = 1
}
groups_users = { }
group_ids . each { | group_id |
2013-06-12 15:59:58 +00:00
groups_users [ group_id ] = [ ]
Group . find ( group_id ) . users . each { | user |
next if ! agents [ user . id ]
groups_users [ group_id ] . push user . id
}
2013-01-04 08:09:59 +00:00
}
# get priorities
ticket_priority_ids = [ ]
Ticket :: Priority . where ( :active = > true ) . each { | priority |
ticket_priority_ids . push priority . id
}
2013-01-04 08:26:14 +00:00
ticket_article_type_ids = [ ]
if params [ :ticket ]
ticket_article_types = [ 'note' , 'phone' ]
if params [ :ticket ] . group . email_address_id
ticket_article_types . push 'email'
end
ticket_article_types . each { | ticket_article_type_name |
ticket_article_type = Ticket :: Article :: Type . lookup ( :name = > ticket_article_type_name )
if ticket_article_type
ticket_article_type_ids . push ticket_article_type . id
end
}
end
2013-01-04 08:09:59 +00:00
return {
2013-01-04 08:26:14 +00:00
:ticket_article_type_id = > ticket_article_type_ids ,
:ticket_state_id = > ticket_state_ids ,
:ticket_priority_id = > ticket_priority_ids ,
:owner_id = > owner_ids ,
:group_id = > group_ids ,
:group_id__owner_id = > groups_users ,
2013-01-04 08:09:59 +00:00
}
end
2012-07-03 13:24:31 +00:00
def merge_to ( data )
2012-11-07 23:47:05 +00:00
2012-07-03 13:24:31 +00:00
# update articles
Ticket :: Article . where ( :ticket_id = > self . id ) . update_all ( [ 'ticket_id = ?' , data [ :ticket_id ] ] )
2012-11-07 23:47:05 +00:00
2012-07-03 13:24:31 +00:00
# update history
2012-11-07 23:47:05 +00:00
2012-07-03 13:24:31 +00:00
# create new merge article
Ticket :: Article . create (
2013-06-12 15:59:58 +00:00
:ticket_id = > self . id ,
2013-01-01 20:29:26 +00:00
:ticket_article_type_id = > Ticket :: Article :: Type . lookup ( :name = > 'note' ) . id ,
:ticket_article_sender_id = > Ticket :: Article :: Sender . lookup ( :name = > 'Agent' ) . id ,
2012-07-03 13:24:31 +00:00
:body = > 'merged' ,
:internal = > false
)
# add history to both
# link tickets
2012-08-21 10:28:41 +00:00
Link . add (
:link_type = > 'parent' ,
:link_object_source = > 'Ticket' ,
:link_object_source_value = > data [ :ticket_id ] ,
:link_object_target = > 'Ticket' ,
:link_object_target_value = > self . id
)
2012-07-03 13:24:31 +00:00
# set state to 'merged'
2013-01-01 20:29:26 +00:00
self . ticket_state_id = Ticket :: State . lookup ( :name = > 'merged' ) . id
2012-07-03 13:24:31 +00:00
# rest owner
2012-08-21 10:28:41 +00:00
self . owner_id = User . where ( :login = > '-' ) . first . id
2012-07-03 13:24:31 +00:00
# save ticket
self . save
end
2013-06-12 15:59:58 +00:00
# def self.agent
# Role.where( :name => ['Agent'], :active => true ).first.users.where( :active => true ).uniq()
# end
2012-04-10 14:06:46 +00:00
def subject_build ( subject )
# clena subject
subject = self . subject_clean ( subject )
ticket_hook = Setting . get ( 'ticket_hook' )
ticket_hook_divider = Setting . get ( 'ticket_hook_divider' )
# none position
if Setting . get ( 'ticket_hook_position' ) == 'none'
return subject
end
# right position
if Setting . get ( 'ticket_hook_position' ) == 'right'
return subject + " [ #{ ticket_hook } #{ ticket_hook_divider } #{ self . number } ] "
end
# left position
return " [ #{ ticket_hook } #{ ticket_hook_divider } #{ self . number } ] " + subject
end
def subject_clean ( subject )
ticket_hook = Setting . get ( 'ticket_hook' )
ticket_hook_divider = Setting . get ( 'ticket_hook_divider' )
ticket_subject_size = Setting . get ( 'ticket_subject_size' )
# remove all possible ticket hook formats with []
subject = subject . gsub / \ [ #{ ticket_hook } : #{ self . number } \ ]( \ s+?|) / , ''
subject = subject . gsub / \ [ #{ ticket_hook } : #{ self . number } \ ]( \ s+?|) / , ''
subject = subject . gsub / \ [ #{ ticket_hook } #{ ticket_hook_divider } #{ self . number } \ ]( \ s+?|) / , ''
# remove all possible ticket hook formats without []
subject = subject . gsub / #{ ticket_hook } : #{ self . number } ( \ s+?|) / , ''
subject = subject . gsub / #{ ticket_hook } : #{ self . number } ( \ s+?|) / , ''
subject = subject . gsub / #{ ticket_hook } #{ ticket_hook_divider } #{ self . number } ( \ s+?|) / , ''
# remove leading "..:\s" and "..[\d+]:\s" e. g. "Re: " or "Re[5]: "
subject = subject . gsub / ^(..( \ [ \ d+ \ ])?: \ s)+ / , ''
# resize subject based on config
if subject . length > ticket_subject_size . to_i
subject = subject [ 0 , ticket_subject_size . to_i ] + '[...]'
end
return subject
end
2013-06-12 15:59:58 +00:00
# ticket.permission(
# :current_user => 123
# )
2012-09-04 21:28:49 +00:00
def permission ( data )
# check customer
if data [ :current_user ] . is_role ( 'Customer' )
2012-11-13 10:34:45 +00:00
# access ok if its own ticket
2012-09-04 21:28:49 +00:00
return true if self . customer_id == data [ :current_user ] . id
2012-11-13 10:34:45 +00:00
# access ok if its organization ticket
if data [ :current_user ] . organization_id && self . organization_id
return true if self . organization_id == data [ :current_user ] . organization_id
end
# no access
2012-09-04 21:28:49 +00:00
return false
end
# check agent
2013-06-10 09:44:31 +00:00
# access if requestor is owner
2012-09-04 21:28:49 +00:00
return true if self . owner_id == data [ :current_user ] . id
2013-06-10 09:44:31 +00:00
# access if requestor is in group
2012-09-04 21:28:49 +00:00
data [ :current_user ] . groups . each { | group |
return true if self . group . id == group . id
}
return false
end
2012-07-30 12:05:46 +00:00
2013-06-12 15:59:58 +00:00
# Ticket.search(
# :current_user => 123,
# :query => 'search something',
# :limit => 15,
# )
2013-05-21 22:32:22 +00:00
def self . search ( params )
# get params
query = params [ :query ]
limit = params [ :limit ] || 12
current_user = params [ :current_user ]
conditions = [ ]
if current_user . is_role ( 'Agent' )
group_ids = Group . select ( 'groups.id' ) . joins ( :users ) .
2013-06-12 15:59:58 +00:00
where ( 'groups_users.user_id = ?' , current_user . id ) .
where ( 'groups.active = ?' , true ) .
map ( & :id )
2013-05-21 22:32:22 +00:00
conditions = [ 'group_id IN (?)' , group_ids ]
else
if ! current_user . organization || ( ! current_user . organization . shared || current_user . organization . shared == false )
conditions = [ 'customer_id = ?' , current_user . id ]
else
conditions = [ '( customer_id = ? OR organization_id = ? )' , current_user . id , current_user . organization . id ]
end
end
# do query
tickets_all = Ticket . select ( 'DISTINCT(tickets.id)' ) .
2013-06-12 15:59:58 +00:00
where ( conditions ) .
where ( '( `tickets`.`title` LIKE ? OR `tickets`.`number` LIKE ? OR `ticket_articles`.`body` LIKE ? OR `ticket_articles`.`from` LIKE ? OR `ticket_articles`.`to` LIKE ? OR `ticket_articles`.`subject` LIKE ?)' , " % #{ query } % " , " % #{ query } % " , " % #{ query } % " , " % #{ query } % " , " % #{ query } % " , " % #{ query } % " ) .
joins ( :articles ) .
limit ( limit ) .
order ( '`tickets`.`created_at` DESC' )
2013-05-21 22:32:22 +00:00
# build result list
tickets = [ ]
users = { }
tickets_all . each do | ticket |
ticket_tmp = Ticket . lookup ( :id = > ticket . id )
tickets . push ticket_tmp
end
return tickets
end
2013-06-12 15:59:58 +00:00
# Ticket.overview_list(
# :current_user => 123,
# )
2012-07-30 12:05:46 +00:00
def self . overview_list ( data )
2012-11-13 10:34:45 +00:00
# get customer overviews
2012-09-04 21:28:49 +00:00
if data [ :current_user ] . is_role ( 'Customer' )
role = data [ :current_user ] . is_role ( 'Customer' )
2012-11-13 10:34:45 +00:00
if data [ :current_user ] . organization_id && data [ :current_user ] . organization . shared
2013-02-01 00:20:18 +00:00
overviews = Overview . where ( :role_id = > role . id , :active = > true )
2012-11-13 10:34:45 +00:00
else
2013-02-01 00:20:18 +00:00
overviews = Overview . where ( :role_id = > role . id , :organization_shared = > false , :active = > true )
2012-11-13 10:34:45 +00:00
end
return overviews
2012-09-04 21:28:49 +00:00
end
2012-11-13 10:34:45 +00:00
# get agent overviews
role = data [ :current_user ] . is_role ( 'Agent' )
2013-02-01 00:20:18 +00:00
overviews = Overview . where ( :role_id = > role . id , :active = > true )
2012-11-13 10:34:45 +00:00
return overviews
2012-07-30 12:05:46 +00:00
end
2013-06-12 15:59:58 +00:00
# Ticket.overview(
# :view => 'some_view_url',
# :current_user => OBJECT,
# )
2012-07-20 11:23:09 +00:00
def self . overview ( data )
2012-11-13 10:34:45 +00:00
overviews = self . overview_list ( data )
2012-09-04 21:28:49 +00:00
2012-07-20 11:23:09 +00:00
# build up attributes hash
overview_selected = nil
overview_selected_raw = nil
2012-11-13 10:34:45 +00:00
overviews . each { | overview |
2012-07-23 22:22:23 +00:00
2012-07-20 11:23:09 +00:00
# remember selected view
2013-01-31 23:44:25 +00:00
if data [ :view ] && data [ :view ] == overview . link
2012-07-20 11:23:09 +00:00
overview_selected = overview
overview_selected_raw = Marshal . load ( Marshal . dump ( overview . attributes ) )
end
2012-11-13 10:34:45 +00:00
# replace e.g. 'current_user.id' with current_user.id
2012-07-20 11:23:09 +00:00
overview . condition . each { | item , value |
2012-11-13 10:34:45 +00:00
if value && value . class . to_s == 'String'
parts = value . split ( '.' , 2 )
if parts [ 0 ] && parts [ 1 ] && parts [ 0 ] == 'current_user'
overview . condition [ item ] = data [ :current_user ] [ parts [ 1 ] . to_sym ]
end
2012-07-20 11:23:09 +00:00
end
}
}
2012-11-26 23:22:52 +00:00
if data [ :view ] && ! overview_selected
return
end
2012-07-20 11:23:09 +00:00
# sortby
2013-06-12 15:59:58 +00:00
# prio
# state
# group
# customer
2012-11-13 10:34:45 +00:00
2012-07-20 11:23:09 +00:00
# order
2013-06-12 15:59:58 +00:00
# asc
# desc
2012-11-13 10:34:45 +00:00
2012-07-20 11:23:09 +00:00
# groupby
2013-06-12 15:59:58 +00:00
# prio
# state
# group
# customer
2012-07-20 11:23:09 +00:00
2013-06-12 15:59:58 +00:00
# all = attributes[:myopenassigned]
# all.merge( { :group_id => groups } )
2012-07-20 11:23:09 +00:00
2013-06-12 15:59:58 +00:00
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
2012-07-20 11:23:09 +00:00
# get only tickets with permissions
2012-09-04 21:28:49 +00:00
if data [ :current_user ] . is_role ( 'Customer' )
group_ids = Group . select ( 'groups.id' ) .
2013-06-12 15:59:58 +00:00
where ( 'groups.active = ?' , true ) .
map ( & :id )
2012-09-04 21:28:49 +00:00
else
group_ids = Group . select ( 'groups.id' ) . joins ( :users ) .
2013-06-12 15:59:58 +00:00
where ( 'groups_users.user_id = ?' , [ data [ :current_user ] . id ] ) .
where ( 'groups.active = ?' , true ) .
map ( & :id )
2012-09-04 21:28:49 +00:00
end
2012-07-20 11:23:09 +00:00
# overview meta for navbar
if ! overview_selected
# loop each overview
result = [ ]
overviews . each { | overview |
# get count
2013-03-13 01:19:20 +00:00
count = Ticket . where ( :group_id = > group_ids ) . where ( self . _condition ( overview . condition ) ) . count ( )
2012-07-23 22:22:23 +00:00
2012-07-20 11:23:09 +00:00
# get meta info
2013-01-31 23:44:25 +00:00
all = {
:name = > overview . name ,
:prio = > overview . prio ,
:link = > overview . link ,
}
2012-07-23 22:22:23 +00:00
2012-07-20 11:23:09 +00:00
# push to result data
result . push all . merge ( { :count = > count } )
}
return result
end
2012-07-20 13:47:04 +00:00
# get result list
if data [ :array ]
2012-11-03 16:45:57 +00:00
order_by = overview_selected [ :order ] [ :by ] . to_s + ' ' + overview_selected [ :order ] [ :direction ] . to_s
if overview_selected . group_by && ! overview_selected . group_by . empty?
order_by = overview_selected . group_by + '_id, ' + order_by
end
2012-07-20 13:47:04 +00:00
tickets = Ticket . select ( 'id' ) .
2013-06-12 15:59:58 +00:00
where ( :group_id = > group_ids ) .
where ( self . _condition ( overview_selected . condition ) ) .
order ( order_by ) .
limit ( 500 )
2012-07-20 13:47:04 +00:00
2012-08-03 22:46:05 +00:00
ticket_ids = [ ]
tickets . each { | ticket |
ticket_ids . push ticket . id
}
2012-07-20 13:47:04 +00:00
tickets_count = Ticket . where ( :group_id = > group_ids ) .
2013-06-12 15:59:58 +00:00
where ( self . _condition ( overview_selected . condition ) ) .
count ( )
2012-07-20 13:47:04 +00:00
return {
2012-11-26 23:22:52 +00:00
:ticket_list = > ticket_ids ,
2012-07-20 13:47:04 +00:00
:tickets_count = > tickets_count ,
:overview = > overview_selected_raw ,
}
end
2012-07-20 11:23:09 +00:00
# get tickets for overview
data [ :start_page ] || = 1
tickets = Ticket . where ( :group_id = > group_ids ) .
2013-06-12 15:59:58 +00:00
where ( self . _condition ( overview_selected . condition ) ) .
order ( overview_selected [ :order ] [ :by ] . to_s + ' ' + overview_selected [ :order ] [ :direction ] . to_s ) #.
# limit( overview_selected.view[ data[:view_mode].to_sym ][:per_page] ).
# offset( overview_selected.view[ data[:view_mode].to_sym ][:per_page].to_i * ( data[:start_page].to_i - 1 ) )
2012-07-20 11:23:09 +00:00
tickets_count = Ticket . where ( :group_id = > group_ids ) .
2013-06-12 15:59:58 +00:00
where ( self . _condition ( overview_selected . condition ) ) .
count ( )
2012-07-20 11:23:09 +00:00
return {
:tickets = > tickets ,
:tickets_count = > tickets_count ,
:overview = > overview_selected_raw ,
}
end
2013-03-13 01:19:20 +00:00
def self . _condition ( condition )
sql = ''
bind = [ nil ]
condition . each { | key , value |
if sql != ''
sql += ' AND '
end
if value . class == Array
sql += " #{ key } IN (?) "
bind . push value
elsif value . class == Hash || value . class == ActiveSupport :: HashWithIndifferentAccess
time = Time . now
if value [ 'area' ] == 'minute'
if value [ 'direction' ] == 'last'
time -= value [ 'count' ] . to_i * 60
else
time += value [ 'count' ] . to_i * 60
end
elsif value [ 'area' ] == 'hour'
if value [ 'direction' ] == 'last'
time -= value [ 'count' ] . to_i * 60 * 60
else
time += value [ 'count' ] . to_i * 60 * 60
end
elsif value [ 'area' ] == 'day'
if value [ 'direction' ] == 'last'
time -= value [ 'count' ] . to_i * 60 * 60 * 24
else
time += value [ 'count' ] . to_i * 60 * 60 * 24
end
elsif value [ 'area' ] == 'month'
if value [ 'direction' ] == 'last'
time -= value [ 'count' ] . to_i * 60 * 60 * 24 * 31
else
time += value [ 'count' ] . to_i * 60 * 60 * 24 * 31
end
elsif value [ 'area' ] == 'year'
if value [ 'direction' ] == 'last'
time -= value [ 'count' ] . to_i * 60 * 60 * 24 * 365
else
time += value [ 'count' ] . to_i * 60 * 60 * 24 * 365
end
end
if value [ 'direction' ] == 'last'
sql += " #{ key } > ? "
bind . push time
else
sql += " #{ key } < ? "
bind . push time
end
else
sql += " #{ key } = ? "
bind . push value
end
}
bind [ 0 ] = sql
return bind
end
2012-07-20 11:23:09 +00:00
2013-03-07 07:13:56 +00:00
def self . escalation_calculation_rebuild
2013-08-06 09:23:25 +00:00
ticket_state_list_open = Ticket :: State . by_category ( 'open' )
2013-08-06 09:49:56 +00:00
2013-03-07 07:13:56 +00:00
tickets = Ticket . where ( :ticket_state_id = > ticket_state_list_open )
tickets . each { | ticket |
ticket . escalation_calculation
}
end
2013-06-07 14:01:04 +00:00
def _escalation_calculation_get_sla
2013-03-05 12:31:23 +00:00
sla_selected = nil
2013-04-30 12:13:53 +00:00
sla_list = Cache . get ( 'SLA::List::Active' )
if sla_list == nil
sla_list = Sla . where ( :active = > true ) . all
Cache . write ( 'SLA::List::Active' , sla_list , { :expires_in = > 1 . hour } )
end
sla_list . each { | sla |
2013-03-22 07:11:20 +00:00
if ! sla . condition || sla . condition . empty?
sla_selected = sla
elsif sla . condition
2013-03-05 12:31:23 +00:00
hit = false
2013-03-07 07:13:56 +00:00
map = [
[ 'tickets.ticket_priority_id' , 'ticket_priority_id' ] ,
[ 'tickets.group_id' , 'group_id' ]
]
map . each { | item |
if sla . condition [ item [ 0 ] ]
if sla . condition [ item [ 0 ] ] . class == String
sla . condition [ item [ 0 ] ] = [ sla . condition [ item [ 0 ] ] ]
end
if sla . condition [ item [ 0 ] ] . include? ( self [ item [ 1 ] ] . to_s )
hit = true
else
hit = false
end
2013-03-05 12:31:23 +00:00
end
2013-03-07 07:13:56 +00:00
}
2013-03-05 12:31:23 +00:00
if hit
sla_selected = sla
end
end
}
2013-03-07 07:13:56 +00:00
2013-03-22 07:11:20 +00:00
return sla_selected
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
# set escalation off if ticket is already closed
2013-08-06 09:49:56 +00:00
ticket_state = Ticket :: State . lookup ( :id = > self . ticket_state_id )
if ticket_state . ignore_escalation?
2013-03-22 07:11:20 +00:00
self . escalation_time = nil
2013-06-12 15:59:58 +00:00
# self.first_response_escal_date = nil
# self.close_time_escal_date = nil
2013-03-28 23:13:15 +00:00
self . callback_loop = true
2013-03-22 07:11:20 +00:00
self . save
return true
end
# get sla for ticket
2013-06-07 14:01:04 +00:00
sla_selected = self . _escalation_calculation_get_sla
2013-03-22 07:11:20 +00:00
2013-03-07 08:01:46 +00:00
# reset escalation if no sla is set
if ! sla_selected
self . escalation_time = nil
2013-06-12 15:59:58 +00:00
# self.first_response_escal_date = nil
# self.close_time_escal_date = nil
2013-03-28 23:13:15 +00:00
self . callback_loop = true
2013-03-07 08:01:46 +00:00
self . save
return true
end
2013-03-05 12:31:23 +00:00
2013-06-12 15:59:58 +00:00
# puts sla_selected.inspect
# puts days.inspect
2013-03-07 07:13:56 +00:00
self . escalation_time = nil
self . first_response_escal_date = nil
2013-03-22 07:11:20 +00:00
self . update_time_escal_date = nil
2013-03-07 07:13:56 +00:00
self . close_time_escal_date = nil
2013-03-05 12:31:23 +00:00
# first response
if sla_selected . first_response_time
2013-06-13 15:03:08 +00:00
# get escalation date without pending time
self . first_response_escal_date = TimeCalculation . dest_time ( self . created_at , sla_selected . first_response_time , sla_selected . data , sla_selected . timezone )
# get pending time between created and first response escal. time
2013-07-19 20:10:35 +00:00
time_in_pending = escalation_suspend ( self . created_at , self . first_response_escal_date , 'relative' , sla_selected , sla_selected . first_response_time )
2013-06-13 15:03:08 +00:00
# get new escalation time (original escal_date + time_in_pending)
self . first_response_escal_date = TimeCalculation . dest_time ( self . first_response_escal_date , time_in_pending . to_i , sla_selected . data , sla_selected . timezone )
2013-03-07 07:13:56 +00:00
# set ticket escalation
2013-03-22 07:11:20 +00:00
self . escalation_time = self . _escalation_calculation_higher_time ( self . escalation_time , self . first_response_escal_date , self . first_response )
2013-03-05 12:31:23 +00:00
end
2013-03-22 07:11:20 +00:00
if self . first_response # && !self.first_response_in_min
2013-06-13 15:03:08 +00:00
# get response time in min between created and first response
self . first_response_in_min = escalation_suspend ( self . created_at , self . first_response , 'real' , sla_selected )
2013-03-05 12:31:23 +00:00
end
2013-06-13 15:03:08 +00:00
# set time to show if sla is raised ot in
2013-03-12 09:45:25 +00:00
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
end
2013-03-23 16:56:18 +00:00
2013-03-22 07:11:20 +00:00
# update time
2013-03-23 16:56:18 +00:00
last_update = self . last_contact_agent
if ! last_update
last_update = self . created_at
end
2013-03-22 07:11:20 +00:00
if sla_selected . update_time
2013-06-07 13:51:56 +00:00
self . update_time_escal_date = TimeCalculation . dest_time ( last_update , sla_selected . update_time , sla_selected . data , sla_selected . timezone )
2013-03-22 07:11:20 +00:00
2013-07-19 20:10:35 +00:00
# get pending time between created and update escal. time
time_in_pending = escalation_suspend ( last_update , self . update_time_escal_date , 'relative' , sla_selected , sla_selected . update_time )
# get new escalation time (original escal_date + time_in_pending)
self . update_time_escal_date = TimeCalculation . dest_time ( self . update_time_escal_date , time_in_pending . to_i , sla_selected . data , sla_selected . timezone )
2013-03-22 07:11:20 +00:00
# set ticket escalation
self . escalation_time = self . _escalation_calculation_higher_time ( self . escalation_time , self . update_time_escal_date , false )
end
2013-03-23 16:56:18 +00:00
if self . last_contact_agent
2013-06-07 13:51:56 +00:00
self . update_time_in_min = TimeCalculation . business_time_diff ( self . created_at , self . last_contact_agent , sla_selected . data , sla_selected . timezone )
2013-03-23 16:56:18 +00:00
end
# set sla time
if sla_selected . update_time && self . update_time_in_min
self . update_time_diff_in_min = sla_selected . update_time - self . update_time_in_min
end
2013-03-22 07:11:20 +00:00
2013-03-05 12:31:23 +00:00
# close time
if sla_selected . close_time
2013-06-13 15:03:08 +00:00
# get escalation date without pending time
2013-06-07 13:51:56 +00:00
self . close_time_escal_date = TimeCalculation . dest_time ( self . created_at , sla_selected . close_time , sla_selected . data , sla_selected . timezone )
2013-03-07 07:13:56 +00:00
2013-06-13 15:03:08 +00:00
# get pending time between created and close escal. time
2013-07-19 20:10:35 +00:00
extended_escalation = escalation_suspend ( self . created_at , self . close_time_escal_date , 'relative' , sla_selected , sla_selected . close_time )
2013-06-13 15:03:08 +00:00
# get new escalation time (original escal_date + time_in_pending)
self . close_time_escal_date = TimeCalculation . dest_time ( self . close_time_escal_date , extended_escalation . to_i , sla_selected . data , sla_selected . timezone )
2013-03-07 07:13:56 +00:00
# set ticket escalation
2013-03-22 07:11:20 +00:00
self . escalation_time = self . _escalation_calculation_higher_time ( self . escalation_time , self . close_time_escal_date , self . close_time )
2013-03-05 12:31:23 +00:00
end
2013-06-13 15:03:08 +00:00
if self . close_time # && !self.close_time_in_min
self . close_time_in_min = escalation_suspend ( self . created_at , self . close_time , 'real' , sla_selected )
2013-03-05 12:31:23 +00:00
end
2013-03-22 07:11:20 +00:00
# set sla time
2013-03-12 09:45:25 +00:00
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
end
2013-03-28 23:13:15 +00:00
self . callback_loop = true
2013-03-05 12:31:23 +00:00
self . save
end
2013-08-06 09:23:25 +00:00
= begin
list tickets by customer groupd in state categroie open and closed
result = Ticket . list_by_customer (
:customer_id = > 123 ,
:limit = > 15 , # optional, default 15
)
returns
result = {
:open = > tickets_open ,
:closed = > tickets_closed ,
}
= end
def self . list_by_customer ( data )
# get closed/open states
ticket_state_list_open = Ticket :: State . by_category ( 'open' )
ticket_state_list_closed = Ticket :: State . by_category ( 'closed' )
# get tickets
tickets_open = Ticket . where (
:customer_id = > data [ :customer_id ] ,
:ticket_state_id = > ticket_state_list_open
) . limit ( data [ :limit ] || 15 ) . order ( 'created_at DESC' )
tickets_closed = Ticket . where (
:customer_id = > data [ :customer_id ] ,
:ticket_state_id = > ticket_state_list_closed
) . limit ( data [ :limit ] || 15 ) . order ( 'created_at DESC' )
return {
:open = > tickets_open ,
:closed = > tickets_closed ,
}
end
2012-11-28 10:03:17 +00:00
private
2012-11-28 09:46:26 +00:00
2013-08-15 22:16:38 +00:00
def check_generate
2013-06-12 15:59:58 +00:00
return if self . number
2013-08-15 22:16:38 +00:00
self . number = Ticket :: Number . generate
2013-06-12 15:59:58 +00:00
end
2013-08-15 22:16:38 +00:00
2013-06-12 15:59:58 +00:00
def check_defaults
if ! self . owner_id
self . owner_id = 1
end
# if self.customer_id && ( !self.organization_id || self.organization_id.empty? )
if self . customer_id
customer = User . find ( self . customer_id )
if self . organization_id != customer . organization_id
self . organization_id = customer . organization_id
2012-11-13 10:34:45 +00:00
end
2012-04-10 14:06:46 +00:00
end
2012-07-23 22:22:23 +00:00
2013-06-14 08:05:42 +00:00
2013-06-12 15:59:58 +00:00
end
def destroy_dependencies
2012-07-20 08:08:31 +00:00
# delete history
2013-06-04 12:52:56 +00:00
History . remove ( 'Ticket' , self . id )
2013-06-12 15:59:58 +00:00
2012-07-20 08:08:31 +00:00
# delete articles
self . articles . destroy_all
end
2013-06-13 19:02:27 +00:00
2013-06-12 14:57:29 +00:00
#type could be:
# real - time without supsend state
2013-06-13 10:00:03 +00:00
# relative - only suspend time
2013-06-12 14:57:29 +00:00
2013-07-19 20:10:35 +00:00
def escalation_suspend ( start_time , end_time , type , sla_selected , sla_time = 0 )
if type == 'relative'
end_time += sla_time * 60
end
2013-06-13 15:03:08 +00:00
total_time_without_pending = 0
2013-06-12 14:57:29 +00:00
total_time = 0
#get history for ticket
2013-06-14 08:16:53 +00:00
history_list = History . list ( 'Ticket' , self . id )
2013-06-12 14:57:29 +00:00
#loop through hist. changes and get time
last_state = nil
last_state_change = nil
last_state_is_pending = false
history_list . each { | history_item |
# ignore if it isn't a state change
2013-06-14 08:05:42 +00:00
next if ! history_item . history_attribute_id
history_attribute = History :: Attribute . lookup ( :id = > history_item . history_attribute_id ) ;
next if history_attribute . name != 'ticket_state'
2013-06-12 14:57:29 +00:00
2013-07-19 20:10:35 +00:00
# ignore all newer state before start_time
next if history_item . created_at < start_time
2013-06-13 15:03:08 +00:00
# ignore all older state changes after end_time
next if last_state_change && last_state_change > end_time
2013-06-12 14:57:29 +00:00
2013-06-13 15:03:08 +00:00
# if created_at is later then end_time, use end_time as last time
2013-06-14 08:05:42 +00:00
if history_item . created_at > end_time
history_item . created_at = end_time
2013-06-12 14:57:29 +00:00
end
# get initial state and time
if ! last_state
2013-06-14 08:05:42 +00:00
last_state = history_item . value_from
2013-06-13 15:05:31 +00:00
last_state_change = start_time
2013-06-12 14:57:29 +00:00
end
2013-07-19 20:10:35 +00:00
# check if time need to be counted
counted = true
if history_item . value_from == 'pending'
counted = false
elsif history_item . value_from == 'close'
counted = false
end
2013-06-12 14:57:29 +00:00
2013-07-19 20:10:35 +00:00
diff = escalation_time_diff ( last_state_change , history_item . created_at , sla_selected )
if counted
puts " Diff count #{ history_item . value_from } -> #{ history_item . value_to } / #{ last_state_change } -> #{ history_item . created_at } "
2013-06-13 15:03:08 +00:00
total_time_without_pending = total_time_without_pending + diff
2013-06-12 14:57:29 +00:00
else
2013-07-19 20:10:35 +00:00
puts " Diff not count #{ history_item . value_from } -> #{ history_item . value_to } / #{ last_state_change } -> #{ history_item . created_at } "
end
total_time = total_time + diff
if history_item . value_to == 'pending'
last_state_is_pending = true
else
2013-06-12 14:57:29 +00:00
last_state_is_pending = false
end
# remember for next loop last state
2013-06-14 08:05:42 +00:00
last_state = history_item . value_to
last_state_change = history_item . created_at
2013-06-12 14:57:29 +00:00
}
# if last state isnt pending, count rest
if ! last_state_is_pending && last_state_change && last_state_change < end_time
2013-06-13 18:38:05 +00:00
diff = escalation_time_diff ( last_state_change , end_time , sla_selected )
2013-06-13 15:03:08 +00:00
puts " Diff count last state was not pending #{ diff . to_s } - #{ last_state_change } - #{ end_time } "
total_time_without_pending = total_time_without_pending + diff
2013-06-12 14:57:29 +00:00
total_time = total_time + diff
end
# if we have not had any state change
if ! last_state_change
2013-06-13 18:38:05 +00:00
diff = escalation_time_diff ( start_time , end_time , sla_selected )
2013-06-13 15:03:08 +00:00
puts 'Diff state has not changed ' + diff . to_s
total_time_without_pending = total_time_without_pending + diff
2013-06-12 14:57:29 +00:00
total_time = total_time + diff
end
2013-06-13 15:03:08 +00:00
2013-06-12 14:57:29 +00:00
#return sum
2013-07-19 20:10:35 +00:00
if type == 'real'
2013-06-13 15:03:08 +00:00
return total_time_without_pending
2013-07-19 20:10:35 +00:00
elsif type == 'relative'
2013-06-13 15:03:08 +00:00
relative = total_time - total_time_without_pending
return relative
2013-06-12 14:57:29 +00:00
else
2013-06-13 15:03:08 +00:00
raise " ERROR: Unknown type #{ type } "
2013-06-12 14:57:29 +00:00
end
end
2012-04-10 14:06:46 +00:00
2013-06-13 15:39:22 +00:00
def escalation_time_diff ( start_time , end_time , sla_selected )
if sla_selected
diff = TimeCalculation . business_time_diff ( start_time , end_time , sla_selected . data , sla_selected . timezone )
else
diff = TimeCalculation . business_time_diff ( start_time , end_time )
end
diff
end
2012-04-10 14:06:46 +00:00
2013-06-07 05:57:52 +00:00
end