Some new rubocop checks.
This commit is contained in:
parent
5b98be93e1
commit
a2d49cefc5
26 changed files with 1178 additions and 1138 deletions
|
@ -31,11 +31,10 @@ returns
|
||||||
|
|
||||||
return data if !self['created_by_id'] && !self['updated_by_id']
|
return data if !self['created_by_id'] && !self['updated_by_id']
|
||||||
['created_by_id', 'updated_by_id'].each {|item|
|
['created_by_id', 'updated_by_id'].each {|item|
|
||||||
if self[ item ]
|
next if !self[ item ]
|
||||||
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
|
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
|
||||||
user = User.lookup( id: self[ item ] )
|
user = User.lookup( id: self[ item ] )
|
||||||
data = user.assets( data )
|
data = user.assets( data )
|
||||||
end
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
|
|
|
@ -16,7 +16,6 @@ class Locale < ApplicationModel
|
||||||
raise "Can't load locales from #{url}: #{result.error}" if !result.success?
|
raise "Can't load locales from #{url}: #{result.error}" if !result.success?
|
||||||
|
|
||||||
result.data.each {|locale|
|
result.data.each {|locale|
|
||||||
puts locale.inspect
|
|
||||||
exists = Locale.where(locale: locale['locale']).first
|
exists = Locale.where(locale: locale['locale']).first
|
||||||
if exists
|
if exists
|
||||||
exists.update(locale.symbolize_keys!)
|
exists.update(locale.symbolize_keys!)
|
||||||
|
|
|
@ -40,11 +40,10 @@ returns
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
['created_by_id', 'updated_by_id'].each {|item|
|
['created_by_id', 'updated_by_id'].each {|item|
|
||||||
if self[ item ]
|
next if !self[ item ]
|
||||||
if !data[ User.to_app_model ][ self[ item ] ]
|
if !data[ User.to_app_model ][ self[ item ] ]
|
||||||
user = User.lookup( id: self[ item ] )
|
user = User.lookup( id: self[ item ] )
|
||||||
data = user.assets( data )
|
data = user.assets( data )
|
||||||
end
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::ActivityStreamLog
|
class Ticket
|
||||||
|
module ActivityStreamLog
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,25 +16,25 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def activity_stream_log (type, user_id)
|
def activity_stream_log (type, user_id)
|
||||||
|
|
||||||
# return if we run import mode
|
# return if we run import mode
|
||||||
return if Setting.get('import_mode')
|
return if Setting.get('import_mode')
|
||||||
|
|
||||||
# return if we run on init mode
|
# return if we run on init mode
|
||||||
return if !Setting.get('system_init_done')
|
return if !Setting.get('system_init_done')
|
||||||
|
|
||||||
return if !self.class.activity_stream_support_config
|
return if !self.class.activity_stream_support_config
|
||||||
role = self.class.activity_stream_support_config[:role]
|
role = self.class.activity_stream_support_config[:role]
|
||||||
ActivityStream.add(
|
ActivityStream.add(
|
||||||
o_id: self['id'],
|
o_id: self['id'],
|
||||||
type: type,
|
type: type,
|
||||||
object: self.class.name,
|
object: self.class.name,
|
||||||
group_id: self['group_id'],
|
group_id: self['group_id'],
|
||||||
role: role,
|
role: role,
|
||||||
created_at: self.updated_at,
|
created_at: self.updated_at,
|
||||||
created_by_id: user_id,
|
created_by_id: user_id,
|
||||||
)
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,50 +1,52 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::Article < ApplicationModel
|
class Ticket
|
||||||
load 'ticket/article/assets.rb'
|
class Article < ApplicationModel
|
||||||
include Ticket::Article::Assets
|
load 'ticket/article/assets.rb'
|
||||||
load 'ticket/article/history_log.rb'
|
include Ticket::Article::Assets
|
||||||
include Ticket::Article::HistoryLog
|
load 'ticket/article/history_log.rb'
|
||||||
load 'ticket/article/activity_stream_log.rb'
|
include Ticket::Article::HistoryLog
|
||||||
include Ticket::Article::ActivityStreamLog
|
load 'ticket/article/activity_stream_log.rb'
|
||||||
|
include Ticket::Article::ActivityStreamLog
|
||||||
|
|
||||||
belongs_to :ticket
|
belongs_to :ticket
|
||||||
belongs_to :type, class_name: 'Ticket::Article::Type'
|
belongs_to :type, class_name: 'Ticket::Article::Type'
|
||||||
belongs_to :sender, class_name: 'Ticket::Article::Sender'
|
belongs_to :sender, class_name: 'Ticket::Article::Sender'
|
||||||
belongs_to :created_by, class_name: 'User'
|
belongs_to :created_by, class_name: 'User'
|
||||||
belongs_to :updated_by, class_name: 'User'
|
belongs_to :updated_by, class_name: 'User'
|
||||||
before_create :check_subject
|
before_create :check_subject
|
||||||
before_update :check_subject
|
before_update :check_subject
|
||||||
notify_clients_support
|
notify_clients_support
|
||||||
|
|
||||||
activity_stream_support ignore_attributes: {
|
activity_stream_support ignore_attributes: {
|
||||||
type_id: true,
|
type_id: true,
|
||||||
sender_id: true,
|
sender_id: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
history_support ignore_attributes: {
|
history_support ignore_attributes: {
|
||||||
type_id: true,
|
type_id: true,
|
||||||
sender_id: true,
|
sender_id: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def check_subject
|
def check_subject
|
||||||
if self.subject
|
if self.subject
|
||||||
self.subject.gsub!(/\s|\t|\r/, ' ')
|
self.subject.gsub!(/\s|\t|\r/, ' ')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Flag < ApplicationModel
|
||||||
|
end
|
||||||
|
|
||||||
|
class Sender < ApplicationModel
|
||||||
|
validates :name, presence: true
|
||||||
|
latest_change_support
|
||||||
|
end
|
||||||
|
|
||||||
|
class Type < ApplicationModel
|
||||||
|
validates :name, presence: true
|
||||||
|
latest_change_support
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Flag < ApplicationModel
|
|
||||||
end
|
|
||||||
|
|
||||||
class Sender < ApplicationModel
|
|
||||||
validates :name, presence: true
|
|
||||||
latest_change_support
|
|
||||||
end
|
|
||||||
|
|
||||||
class Type < ApplicationModel
|
|
||||||
validates :name, presence: true
|
|
||||||
latest_change_support
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Article::ActivityStreamLog
|
class Ticket
|
||||||
|
class Article
|
||||||
|
module ActivityStreamLog
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,26 +17,27 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def activity_stream_log (type, user_id)
|
def activity_stream_log (type, user_id)
|
||||||
|
|
||||||
# return if we run import mode
|
# return if we run import mode
|
||||||
return if Setting.get('import_mode')
|
return if Setting.get('import_mode')
|
||||||
|
|
||||||
# return if we run on init mode
|
# return if we run on init mode
|
||||||
return if !Setting.get('system_init_done')
|
return if !Setting.get('system_init_done')
|
||||||
|
|
||||||
return if !self.class.activity_stream_support_config
|
return if !self.class.activity_stream_support_config
|
||||||
role = self.class.activity_stream_support_config[:role]
|
role = self.class.activity_stream_support_config[:role]
|
||||||
ticket = Ticket.lookup( id: self.ticket_id )
|
ticket = Ticket.lookup( id: self.ticket_id )
|
||||||
ActivityStream.add(
|
ActivityStream.add(
|
||||||
o_id: self['id'],
|
o_id: self['id'],
|
||||||
type: type,
|
type: type,
|
||||||
object: self.class.name,
|
object: self.class.name,
|
||||||
group_id: ticket.group_id,
|
group_id: ticket.group_id,
|
||||||
role: role,
|
role: role,
|
||||||
created_at: self.updated_at,
|
created_at: self.updated_at,
|
||||||
created_by_id: user_id,
|
created_by_id: user_id,
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Article::Assets
|
class Ticket
|
||||||
|
class Article
|
||||||
|
module Assets
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -21,35 +23,35 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def assets (data)
|
def assets (data)
|
||||||
|
|
||||||
if !data[ Ticket.to_app_model ]
|
if !data[ Ticket.to_app_model ]
|
||||||
data[ Ticket.to_app_model ] = {}
|
data[ Ticket.to_app_model ] = {}
|
||||||
end
|
end
|
||||||
if !data[ Ticket.to_app_model ][ self.ticket_id ]
|
if !data[ Ticket.to_app_model ][ self.ticket_id ]
|
||||||
ticket = Ticket.find( self.ticket_id )
|
ticket = Ticket.find( self.ticket_id )
|
||||||
data = ticket.assets(data)
|
data = ticket.assets(data)
|
||||||
end
|
|
||||||
|
|
||||||
if !data[ Ticket::Article.to_app_model ]
|
|
||||||
data[ Ticket::Article.to_app_model ] = {}
|
|
||||||
end
|
|
||||||
if !data[ Ticket::Article.to_app_model ][ self.id ]
|
|
||||||
data[ Ticket::Article.to_app_model ][ self.id ] = self.attributes
|
|
||||||
|
|
||||||
# add attachment list to article
|
|
||||||
data[ Ticket::Article.to_app_model ][ self.id ]['attachments'] = self.attachments
|
|
||||||
end
|
|
||||||
|
|
||||||
['created_by_id', 'updated_by_id'].each {|item|
|
|
||||||
if self[ item ]
|
|
||||||
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
|
|
||||||
user = User.lookup( id: self[ item ] )
|
|
||||||
data = user.assets( data )
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
}
|
|
||||||
data
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if !data[ Ticket::Article.to_app_model ]
|
||||||
|
data[ Ticket::Article.to_app_model ] = {}
|
||||||
|
end
|
||||||
|
if !data[ Ticket::Article.to_app_model ][ self.id ]
|
||||||
|
data[ Ticket::Article.to_app_model ][ self.id ] = self.attributes
|
||||||
|
|
||||||
|
# add attachment list to article
|
||||||
|
data[ Ticket::Article.to_app_model ][ self.id ]['attachments'] = self.attachments
|
||||||
|
end
|
||||||
|
|
||||||
|
['created_by_id', 'updated_by_id'].each {|item|
|
||||||
|
next if !self[ item ]
|
||||||
|
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
|
||||||
|
user = User.lookup( id: self[ item ] )
|
||||||
|
data = user.assets( data )
|
||||||
|
end
|
||||||
|
}
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Article::HistoryLog
|
class Ticket
|
||||||
|
class Article
|
||||||
|
module HistoryLog
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,17 +17,18 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def history_log (type, user_id, data = {})
|
def history_log (type, user_id, data = {})
|
||||||
|
|
||||||
# if Ticketdata[:data[:Article has changed, remember related ticket to be able
|
# if Ticketdata[:data[:Article has changed, remember related ticket to be able
|
||||||
# to show article changes in ticket history
|
# to show article changes in ticket history
|
||||||
data[:o_id] = self['id']
|
data[:o_id] = self['id']
|
||||||
data[:history_type] = type
|
data[:history_type] = type
|
||||||
data[:history_object] = self.class.name
|
data[:history_object] = self.class.name
|
||||||
data[:related_o_id] = self['ticket_id']
|
data[:related_o_id] = self['ticket_id']
|
||||||
data[:related_history_object] = 'Ticket'
|
data[:related_history_object] = 'Ticket'
|
||||||
data[:created_by_id] = user_id
|
data[:created_by_id] = user_id
|
||||||
History.add(data)
|
History.add(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Assets
|
class Ticket
|
||||||
|
module Assets
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -21,23 +22,22 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def assets (data)
|
def assets (data)
|
||||||
|
|
||||||
if !data[ Ticket.to_app_model ]
|
if !data[ Ticket.to_app_model ]
|
||||||
data[ Ticket.to_app_model ] = {}
|
data[ Ticket.to_app_model ] = {}
|
||||||
end
|
end
|
||||||
if !data[ Ticket.to_app_model ][ self.id ]
|
if !data[ Ticket.to_app_model ][ self.id ]
|
||||||
data[ Ticket.to_app_model ][ self.id ] = self.attributes_with_associations
|
data[ Ticket.to_app_model ][ self.id ] = self.attributes_with_associations
|
||||||
end
|
end
|
||||||
['created_by_id', 'updated_by_id', 'owner_id', 'customer_id'].each {|item|
|
['created_by_id', 'updated_by_id', 'owner_id', 'customer_id'].each {|item|
|
||||||
if self[ item ]
|
next if !self[ item ]
|
||||||
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
|
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
|
||||||
user = User.lookup( id: self[ item ] )
|
user = User.lookup( id: self[ item ] )
|
||||||
data = user.assets( data )
|
data = user.assets( data )
|
||||||
end
|
end
|
||||||
end
|
}
|
||||||
}
|
data
|
||||||
data
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::Counter < ApplicationModel
|
class Ticket
|
||||||
|
class Counter < ApplicationModel
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Escalation
|
class Ticket
|
||||||
|
module Escalation
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -14,14 +15,14 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.rebuild_all
|
def self.rebuild_all
|
||||||
state_list_open = Ticket::State.by_category( 'open' )
|
state_list_open = Ticket::State.by_category( 'open' )
|
||||||
|
|
||||||
tickets = Ticket.where( state_id: state_list_open )
|
tickets = Ticket.where( state_id: state_list_open )
|
||||||
tickets.each {|ticket|
|
tickets.each {|ticket|
|
||||||
ticket.escalation_calculation
|
ticket.escalation_calculation
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -36,128 +37,128 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def escalation_calculation
|
def escalation_calculation
|
||||||
|
|
||||||
# set escalation off if ticket is already closed
|
# set escalation off if ticket is already closed
|
||||||
state = Ticket::State.lookup( id: self.state_id )
|
state = Ticket::State.lookup( id: self.state_id )
|
||||||
if state.ignore_escalation?
|
if state.ignore_escalation?
|
||||||
|
|
||||||
# nothing to change
|
# nothing to change
|
||||||
return true if !self.escalation_time
|
return true if !self.escalation_time
|
||||||
|
|
||||||
|
self.escalation_time = nil
|
||||||
|
# self.first_response_escal_date = nil
|
||||||
|
# self.close_time_escal_date = nil
|
||||||
|
self.callback_loop = true
|
||||||
|
self.save
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
# get sla for ticket
|
||||||
|
sla_selected = escalation_calculation_get_sla
|
||||||
|
|
||||||
|
# reset escalation if no sla is set
|
||||||
|
if !sla_selected
|
||||||
|
|
||||||
|
# nothing to change
|
||||||
|
return true if !self.escalation_time
|
||||||
|
|
||||||
|
self.escalation_time = nil
|
||||||
|
# self.first_response_escal_date = nil
|
||||||
|
# self.close_time_escal_date = nil
|
||||||
|
self.callback_loop = true
|
||||||
|
self.save
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
# puts sla_selected.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.close_time_escal_date = nil
|
self.update_time_escal_date = nil
|
||||||
self.callback_loop = true
|
self.close_time_escal_date = nil
|
||||||
self.save
|
|
||||||
return true
|
# first response
|
||||||
|
if sla_selected.first_response_time
|
||||||
|
|
||||||
|
# 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
|
||||||
|
time_in_pending = escalation_suspend( self.created_at, self.first_response_escal_date, 'relative', sla_selected, sla_selected.first_response_time )
|
||||||
|
|
||||||
|
# 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 )
|
||||||
|
|
||||||
|
# set ticket escalation
|
||||||
|
self.escalation_time = calculation_higher_time( self.escalation_time, self.first_response_escal_date, self.first_response )
|
||||||
|
end
|
||||||
|
if self.first_response# && !self.first_response_in_min
|
||||||
|
|
||||||
|
# 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 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# set time to show if sla is raised ot in
|
||||||
|
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
|
||||||
|
|
||||||
|
# update time
|
||||||
|
last_update = self.last_contact_agent
|
||||||
|
if !last_update
|
||||||
|
last_update = self.created_at
|
||||||
|
end
|
||||||
|
if sla_selected.update_time
|
||||||
|
self.update_time_escal_date = TimeCalculation.dest_time( last_update, sla_selected.update_time, sla_selected.data, sla_selected.timezone )
|
||||||
|
|
||||||
|
# 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 )
|
||||||
|
|
||||||
|
# set ticket escalation
|
||||||
|
self.escalation_time = calculation_higher_time( self.escalation_time, self.update_time_escal_date, false )
|
||||||
|
end
|
||||||
|
if self.last_contact_agent
|
||||||
|
self.update_time_in_min = TimeCalculation.business_time_diff( self.created_at, self.last_contact_agent, sla_selected.data, sla_selected.timezone )
|
||||||
|
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
|
||||||
|
|
||||||
|
# close time
|
||||||
|
if sla_selected.close_time
|
||||||
|
|
||||||
|
# get escalation date without pending time
|
||||||
|
self.close_time_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.close_time, sla_selected.data, sla_selected.timezone )
|
||||||
|
|
||||||
|
# get pending time between created and close escal. time
|
||||||
|
extended_escalation = escalation_suspend( self.created_at, self.close_time_escal_date, 'relative', sla_selected, sla_selected.close_time )
|
||||||
|
|
||||||
|
# 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 )
|
||||||
|
|
||||||
|
# set ticket escalation
|
||||||
|
self.escalation_time = calculation_higher_time( self.escalation_time, self.close_time_escal_date, self.close_time )
|
||||||
|
end
|
||||||
|
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 )
|
||||||
|
end
|
||||||
|
# set sla time
|
||||||
|
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
|
||||||
|
if self.changed?
|
||||||
|
self.callback_loop = true
|
||||||
|
self.save
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# get sla for ticket
|
|
||||||
sla_selected = escalation_calculation_get_sla
|
|
||||||
|
|
||||||
# reset escalation if no sla is set
|
|
||||||
if !sla_selected
|
|
||||||
|
|
||||||
# nothing to change
|
|
||||||
return true if !self.escalation_time
|
|
||||||
|
|
||||||
self.escalation_time = nil
|
|
||||||
# self.first_response_escal_date = nil
|
|
||||||
# self.close_time_escal_date = nil
|
|
||||||
self.callback_loop = true
|
|
||||||
self.save
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
# puts sla_selected.inspect
|
|
||||||
# puts days.inspect
|
|
||||||
self.escalation_time = nil
|
|
||||||
self.first_response_escal_date = nil
|
|
||||||
self.update_time_escal_date = nil
|
|
||||||
self.close_time_escal_date = nil
|
|
||||||
|
|
||||||
# first response
|
|
||||||
if sla_selected.first_response_time
|
|
||||||
|
|
||||||
# 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
|
|
||||||
time_in_pending = escalation_suspend( self.created_at, self.first_response_escal_date, 'relative', sla_selected, sla_selected.first_response_time )
|
|
||||||
|
|
||||||
# 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 )
|
|
||||||
|
|
||||||
# set ticket escalation
|
|
||||||
self.escalation_time = calculation_higher_time( self.escalation_time, self.first_response_escal_date, self.first_response )
|
|
||||||
end
|
|
||||||
if self.first_response# && !self.first_response_in_min
|
|
||||||
|
|
||||||
# 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 )
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# set time to show if sla is raised ot in
|
|
||||||
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
|
|
||||||
|
|
||||||
# update time
|
|
||||||
last_update = self.last_contact_agent
|
|
||||||
if !last_update
|
|
||||||
last_update = self.created_at
|
|
||||||
end
|
|
||||||
if sla_selected.update_time
|
|
||||||
self.update_time_escal_date = TimeCalculation.dest_time( last_update, sla_selected.update_time, sla_selected.data, sla_selected.timezone )
|
|
||||||
|
|
||||||
# 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 )
|
|
||||||
|
|
||||||
# set ticket escalation
|
|
||||||
self.escalation_time = calculation_higher_time( self.escalation_time, self.update_time_escal_date, false )
|
|
||||||
end
|
|
||||||
if self.last_contact_agent
|
|
||||||
self.update_time_in_min = TimeCalculation.business_time_diff( self.created_at, self.last_contact_agent, sla_selected.data, sla_selected.timezone )
|
|
||||||
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
|
|
||||||
|
|
||||||
# close time
|
|
||||||
if sla_selected.close_time
|
|
||||||
|
|
||||||
# get escalation date without pending time
|
|
||||||
self.close_time_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.close_time, sla_selected.data, sla_selected.timezone )
|
|
||||||
|
|
||||||
# get pending time between created and close escal. time
|
|
||||||
extended_escalation = escalation_suspend( self.created_at, self.close_time_escal_date, 'relative', sla_selected, sla_selected.close_time )
|
|
||||||
|
|
||||||
# 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 )
|
|
||||||
|
|
||||||
# set ticket escalation
|
|
||||||
self.escalation_time = calculation_higher_time( self.escalation_time, self.close_time_escal_date, self.close_time )
|
|
||||||
end
|
|
||||||
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 )
|
|
||||||
end
|
|
||||||
# set sla time
|
|
||||||
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
|
|
||||||
if self.changed?
|
|
||||||
self.callback_loop = true
|
|
||||||
self.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
return sla for ticket
|
return sla for ticket
|
||||||
|
@ -171,153 +172,154 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def escalation_calculation_get_sla
|
def escalation_calculation_get_sla
|
||||||
sla_selected = nil
|
sla_selected = nil
|
||||||
sla_list = Cache.get( 'SLA::List::Active' )
|
sla_list = Cache.get( 'SLA::List::Active' )
|
||||||
if sla_list == nil
|
if sla_list == nil
|
||||||
sla_list = Sla.where( active: true )
|
sla_list = Sla.where( active: true )
|
||||||
Cache.write( 'SLA::List::Active', sla_list, { expires_in: 1.hour } )
|
Cache.write( 'SLA::List::Active', sla_list, { expires_in: 1.hour } )
|
||||||
end
|
end
|
||||||
sla_list.each {|sla|
|
sla_list.each {|sla|
|
||||||
if !sla.condition || sla.condition.empty?
|
if !sla.condition || sla.condition.empty?
|
||||||
sla_selected = sla
|
|
||||||
elsif sla.condition
|
|
||||||
hit = false
|
|
||||||
map = [
|
|
||||||
[ 'tickets.priority_id', '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
|
|
||||||
end
|
|
||||||
}
|
|
||||||
if hit
|
|
||||||
sla_selected = sla
|
sla_selected = sla
|
||||||
|
elsif sla.condition
|
||||||
|
hit = false
|
||||||
|
map = [
|
||||||
|
[ 'tickets.priority_id', '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
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if hit
|
||||||
|
sla_selected = sla
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
}
|
||||||
}
|
sla_selected
|
||||||
sla_selected
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
#type could be:
|
|
||||||
# real - time without supsend state
|
|
||||||
# relative - only suspend time
|
|
||||||
|
|
||||||
def escalation_suspend (start_time, end_time, type, sla_selected, sla_time = 0)
|
|
||||||
if type == 'relative'
|
|
||||||
end_time += sla_time * 60
|
|
||||||
end
|
end
|
||||||
total_time_without_pending = 0
|
|
||||||
total_time = 0
|
|
||||||
#get history for ticket
|
|
||||||
history_list = self.history_get
|
|
||||||
|
|
||||||
#loop through hist. changes and get time
|
private
|
||||||
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
|
#type could be:
|
||||||
next if !history_item['attribute']
|
# real - time without supsend state
|
||||||
next if history_item['attribute'] != 'state'
|
# relative - only suspend time
|
||||||
|
|
||||||
# ignore all newer state before start_time
|
def escalation_suspend (start_time, end_time, type, sla_selected, sla_time = 0)
|
||||||
next if history_item['created_at'] < start_time
|
if type == 'relative'
|
||||||
|
end_time += sla_time * 60
|
||||||
# ignore all older state changes after end_time
|
|
||||||
next if last_state_change && last_state_change > end_time
|
|
||||||
|
|
||||||
# if created_at is later then end_time, use end_time as last time
|
|
||||||
if history_item['created_at'] > end_time
|
|
||||||
history_item['created_at'] = end_time
|
|
||||||
end
|
end
|
||||||
|
total_time_without_pending = 0
|
||||||
|
total_time = 0
|
||||||
|
#get history for ticket
|
||||||
|
history_list = self.history_get
|
||||||
|
|
||||||
# get initial state and time
|
#loop through hist. changes and get time
|
||||||
if !last_state
|
last_state = nil
|
||||||
last_state = history_item['value_from']
|
last_state_change = nil
|
||||||
last_state_change = start_time
|
last_state_is_pending = false
|
||||||
end
|
history_list.each { |history_item|
|
||||||
|
|
||||||
# check if time need to be counted
|
# ignore if it isn't a state change
|
||||||
counted = true
|
next if !history_item['attribute']
|
||||||
if history_item['value_from'] == 'pending reminder'
|
next if history_item['attribute'] != 'state'
|
||||||
counted = false
|
|
||||||
elsif history_item['value_from'] == 'close'
|
|
||||||
counted = false
|
|
||||||
end
|
|
||||||
|
|
||||||
diff = escalation_time_diff( last_state_change, history_item['created_at'], sla_selected )
|
# ignore all newer state before start_time
|
||||||
if counted
|
next if history_item['created_at'] < start_time
|
||||||
# puts "Diff count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
|
|
||||||
|
# ignore all older state changes after end_time
|
||||||
|
next if last_state_change && last_state_change > end_time
|
||||||
|
|
||||||
|
# if created_at is later then end_time, use end_time as last time
|
||||||
|
if history_item['created_at'] > end_time
|
||||||
|
history_item['created_at'] = end_time
|
||||||
|
end
|
||||||
|
|
||||||
|
# get initial state and time
|
||||||
|
if !last_state
|
||||||
|
last_state = history_item['value_from']
|
||||||
|
last_state_change = start_time
|
||||||
|
end
|
||||||
|
|
||||||
|
# check if time need to be counted
|
||||||
|
counted = true
|
||||||
|
if history_item['value_from'] == 'pending reminder'
|
||||||
|
counted = false
|
||||||
|
elsif history_item['value_from'] == 'close'
|
||||||
|
counted = false
|
||||||
|
end
|
||||||
|
|
||||||
|
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']}"
|
||||||
|
total_time_without_pending = total_time_without_pending + diff
|
||||||
|
else
|
||||||
|
# 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 reminder'
|
||||||
|
last_state_is_pending = true
|
||||||
|
else
|
||||||
|
last_state_is_pending = false
|
||||||
|
end
|
||||||
|
|
||||||
|
# remember for next loop last state
|
||||||
|
last_state = history_item['value_to']
|
||||||
|
last_state_change = history_item['created_at']
|
||||||
|
}
|
||||||
|
|
||||||
|
# if last state isnt pending, count rest
|
||||||
|
if !last_state_is_pending && last_state_change && last_state_change < end_time
|
||||||
|
diff = escalation_time_diff( last_state_change, end_time, sla_selected )
|
||||||
|
# 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
|
total_time_without_pending = total_time_without_pending + diff
|
||||||
else
|
total_time = total_time + diff
|
||||||
# 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 reminder'
|
|
||||||
last_state_is_pending = true
|
|
||||||
else
|
|
||||||
last_state_is_pending = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# remember for next loop last state
|
# if we have not had any state change
|
||||||
last_state = history_item['value_to']
|
if !last_state_change
|
||||||
last_state_change = history_item['created_at']
|
diff = escalation_time_diff( start_time, end_time, sla_selected )
|
||||||
}
|
# puts 'Diff state has not changed ' + diff.to_s
|
||||||
|
total_time_without_pending = total_time_without_pending + diff
|
||||||
|
total_time = total_time + diff
|
||||||
|
end
|
||||||
|
|
||||||
# if last state isnt pending, count rest
|
#return sum
|
||||||
if !last_state_is_pending && last_state_change && last_state_change < end_time
|
if type == 'real'
|
||||||
diff = escalation_time_diff( last_state_change, end_time, sla_selected )
|
return total_time_without_pending
|
||||||
# puts "Diff count last state was not pending #{diff.to_s} - #{last_state_change} - #{end_time}"
|
elsif type == 'relative'
|
||||||
total_time_without_pending = total_time_without_pending + diff
|
relative = total_time - total_time_without_pending
|
||||||
total_time = total_time + diff
|
return relative
|
||||||
|
else
|
||||||
|
raise "ERROR: Unknown type #{type}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# if we have not had any state change
|
def escalation_time_diff( start_time, end_time, sla_selected )
|
||||||
if !last_state_change
|
if sla_selected
|
||||||
diff = escalation_time_diff( start_time, end_time, sla_selected )
|
diff = TimeCalculation.business_time_diff( start_time, end_time, sla_selected.data, sla_selected.timezone)
|
||||||
# puts 'Diff state has not changed ' + diff.to_s
|
else
|
||||||
total_time_without_pending = total_time_without_pending + diff
|
diff = TimeCalculation.business_time_diff( start_time, end_time )
|
||||||
total_time = total_time + diff
|
end
|
||||||
|
diff
|
||||||
end
|
end
|
||||||
|
|
||||||
#return sum
|
def calculation_higher_time(escalation_time, check_time, done_time)
|
||||||
if type == 'real'
|
return escalation_time if done_time
|
||||||
return total_time_without_pending
|
return check_time if !escalation_time
|
||||||
elsif type == 'relative'
|
return escalation_time if !check_time
|
||||||
relative = total_time - total_time_without_pending
|
return check_time if escalation_time > check_time
|
||||||
return relative
|
return escalation_time
|
||||||
else
|
|
||||||
raise "ERROR: Unknown type #{type}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def 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
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::Flag < ApplicationModel
|
class Ticket
|
||||||
|
class Flag < ApplicationModel
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::HistoryLog
|
class Ticket
|
||||||
|
module HistoryLog
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,15 +16,15 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def history_log (type, user_id, data = {})
|
def history_log (type, user_id, data = {})
|
||||||
data[:o_id] = self['id']
|
data[:o_id] = self['id']
|
||||||
data[:history_type] = type
|
data[:history_type] = type
|
||||||
data[:history_object] = self.class.name
|
data[:history_object] = self.class.name
|
||||||
data[:related_o_id] = nil
|
data[:related_o_id] = nil
|
||||||
data[:related_history_object] = nil
|
data[:related_history_object] = nil
|
||||||
data[:created_by_id] = user_id
|
data[:created_by_id] = user_id
|
||||||
History.add(data)
|
History.add(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -57,25 +58,25 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def history_get(fulldata = false)
|
def history_get(fulldata = false)
|
||||||
list = History.list( self.class.name, self['id'], 'Ticket::Article' )
|
list = History.list( self.class.name, self['id'], 'Ticket::Article' )
|
||||||
return list if !fulldata
|
return list if !fulldata
|
||||||
|
|
||||||
# get related objects
|
# get related objects
|
||||||
assets = {}
|
assets = {}
|
||||||
list.each {|item|
|
list.each {|item|
|
||||||
record = Kernel.const_get( item['object'] ).find( item['o_id'] )
|
record = Kernel.const_get( item['object'] ).find( item['o_id'] )
|
||||||
assets = record.assets(assets)
|
|
||||||
|
|
||||||
if item['related_object']
|
|
||||||
record = Kernel.const_get( item['related_object'] ).find( item['related_o_id'] )
|
|
||||||
assets = record.assets(assets)
|
assets = record.assets(assets)
|
||||||
end
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
history: list,
|
|
||||||
assets: assets,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if item['related_object']
|
||||||
|
record = Kernel.const_get( item['related_object'] ).find( item['related_o_id'] )
|
||||||
|
assets = record.assets(assets)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
history: list,
|
||||||
|
assets: assets,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::Number
|
class Ticket
|
||||||
include ApplicationLib
|
class Number
|
||||||
|
include ApplicationLib
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,16 +16,16 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.generate
|
def self.generate
|
||||||
|
|
||||||
# generate number
|
# generate number
|
||||||
(1..50_000).each { |i|
|
(1..50_000).each { |i|
|
||||||
number = adapter.generate
|
number = adapter.generate
|
||||||
ticket = Ticket.where( number: number ).first
|
ticket = Ticket.where( number: number ).first
|
||||||
return number if !ticket
|
return number if !ticket
|
||||||
}
|
}
|
||||||
raise "Can't generate new ticket number!"
|
raise "Can't generate new ticket number!"
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -38,21 +39,22 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.check(string)
|
def self.check(string)
|
||||||
adapter.check(string)
|
adapter.check(string)
|
||||||
end
|
|
||||||
|
|
||||||
def self.adapter
|
|
||||||
|
|
||||||
# load backend based on config
|
|
||||||
adapter_name = Setting.get('ticket_number')
|
|
||||||
if !adapter_name
|
|
||||||
raise 'Missing ticket_number setting option'
|
|
||||||
end
|
end
|
||||||
adapter = load_adapter(adapter_name)
|
|
||||||
if !adapter
|
def self.adapter
|
||||||
raise "Can't load ticket_number adapter '#{adapter_name}'"
|
|
||||||
|
# load backend based on config
|
||||||
|
adapter_name = Setting.get('ticket_number')
|
||||||
|
if !adapter_name
|
||||||
|
raise 'Missing ticket_number setting option'
|
||||||
|
end
|
||||||
|
adapter = load_adapter(adapter_name)
|
||||||
|
if !adapter
|
||||||
|
raise "Can't load ticket_number adapter '#{adapter_name}'"
|
||||||
|
end
|
||||||
|
adapter
|
||||||
end
|
end
|
||||||
adapter
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,83 +1,88 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Number::Date
|
class Ticket
|
||||||
extend self
|
class Number
|
||||||
|
module Date
|
||||||
|
extend self
|
||||||
|
|
||||||
def generate
|
def generate
|
||||||
|
|
||||||
# get config
|
# get config
|
||||||
config = Setting.get('ticket_number_date')
|
config = Setting.get('ticket_number_date')
|
||||||
|
|
||||||
t = Time.now
|
t = Time.zone.now
|
||||||
date = t.strftime('%Y-%m-%d')
|
date = t.strftime('%Y-%m-%d')
|
||||||
|
|
||||||
# read counter
|
# read counter
|
||||||
counter_increment = nil
|
counter_increment = nil
|
||||||
Ticket::Counter.transaction do
|
Ticket::Counter.transaction do
|
||||||
counter = Ticket::Counter.where( generator: 'Date' ).lock(true).first
|
counter = Ticket::Counter.where( generator: 'Date' ).lock(true).first
|
||||||
if !counter
|
if !counter
|
||||||
counter = Ticket::Counter.new( generator: 'Date', content: '0' )
|
counter = Ticket::Counter.new( generator: 'Date', content: '0' )
|
||||||
end
|
end
|
||||||
|
|
||||||
# increase counter
|
# increase counter
|
||||||
counter_increment, date_file = counter.content.to_s.split(';')
|
counter_increment, date_file = counter.content.to_s.split(';')
|
||||||
if date_file == date
|
if date_file == date
|
||||||
counter_increment = counter_increment.to_i + 1
|
counter_increment = counter_increment.to_i + 1
|
||||||
else
|
else
|
||||||
counter_increment = 1
|
counter_increment = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
# store new counter value
|
# store new counter value
|
||||||
counter.content = counter_increment.to_s + ';' + date
|
counter.content = counter_increment.to_s + ';' + date
|
||||||
counter.save
|
counter.save
|
||||||
end
|
|
||||||
|
|
||||||
system_id = Setting.get('system_id') || ''
|
|
||||||
number = t.strftime('%Y%m%d') + system_id.to_s + sprintf( '%04d', counter_increment)
|
|
||||||
|
|
||||||
# calculate a checksum
|
|
||||||
# The algorithm to calculate the checksum is derived from the one
|
|
||||||
# Deutsche Bundesbahn (german railway company) uses for calculation
|
|
||||||
# of the check digit of their vehikel numbering.
|
|
||||||
# The checksum is calculated by alternately multiplying the digits
|
|
||||||
# with 1 and 2 and adding the resulsts from left to right of the
|
|
||||||
# vehikel number. The modulus to 10 of this sum is substracted from
|
|
||||||
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
|
|
||||||
# (german)
|
|
||||||
if config[:checksum]
|
|
||||||
chksum = 0
|
|
||||||
mult = 1
|
|
||||||
(1..number.length).each do |i|
|
|
||||||
digit = number.to_s[i, 1]
|
|
||||||
chksum = chksum + ( mult * digit.to_i )
|
|
||||||
mult += 1
|
|
||||||
if mult == 3
|
|
||||||
mult = 1
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
chksum %= 10
|
|
||||||
chksum = 10 - chksum
|
|
||||||
if chksum == 10
|
|
||||||
chksum = 1
|
|
||||||
end
|
|
||||||
number += chksum.to_s
|
|
||||||
end
|
|
||||||
number
|
|
||||||
end
|
|
||||||
def check(string)
|
|
||||||
|
|
||||||
# get config
|
system_id = Setting.get('system_id') || ''
|
||||||
system_id = Setting.get('system_id') || ''
|
number = t.strftime('%Y%m%d') + system_id.to_s + sprintf( '%04d', counter_increment)
|
||||||
ticket_hook = Setting.get('ticket_hook')
|
|
||||||
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
|
|
||||||
ticket = nil
|
|
||||||
|
|
||||||
# probe format
|
# calculate a checksum
|
||||||
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,50})/i then
|
# The algorithm to calculate the checksum is derived from the one
|
||||||
ticket = Ticket.where( number: $1 ).first
|
# Deutsche Bundesbahn (german railway company) uses for calculation
|
||||||
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,50})/i then
|
# of the check digit of their vehikel numbering.
|
||||||
ticket = Ticket.where( number: $1 ).first
|
# The checksum is calculated by alternately multiplying the digits
|
||||||
|
# with 1 and 2 and adding the resulsts from left to right of the
|
||||||
|
# vehikel number. The modulus to 10 of this sum is substracted from
|
||||||
|
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
|
||||||
|
# (german)
|
||||||
|
if config[:checksum]
|
||||||
|
chksum = 0
|
||||||
|
mult = 1
|
||||||
|
(1..number.length).each do |i|
|
||||||
|
digit = number.to_s[i, 1]
|
||||||
|
chksum = chksum + ( mult * digit.to_i )
|
||||||
|
mult += 1
|
||||||
|
if mult == 3
|
||||||
|
mult = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
chksum %= 10
|
||||||
|
chksum = 10 - chksum
|
||||||
|
if chksum == 10
|
||||||
|
chksum = 1
|
||||||
|
end
|
||||||
|
number += chksum.to_s
|
||||||
|
end
|
||||||
|
number
|
||||||
|
end
|
||||||
|
|
||||||
|
def check(string)
|
||||||
|
|
||||||
|
# get config
|
||||||
|
system_id = Setting.get('system_id') || ''
|
||||||
|
ticket_hook = Setting.get('ticket_hook')
|
||||||
|
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
|
||||||
|
ticket = nil
|
||||||
|
|
||||||
|
# probe format
|
||||||
|
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,50})/i
|
||||||
|
ticket = Ticket.where( number: $1 ).first
|
||||||
|
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,50})/i
|
||||||
|
ticket = Ticket.where( number: $1 ).first
|
||||||
|
end
|
||||||
|
ticket
|
||||||
|
end
|
||||||
end
|
end
|
||||||
ticket
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,87 +1,91 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Number::Increment
|
class Ticket
|
||||||
extend self
|
class Number
|
||||||
|
module Increment
|
||||||
|
extend self
|
||||||
|
|
||||||
def generate
|
def generate
|
||||||
|
|
||||||
# get config
|
# get config
|
||||||
config = Setting.get('ticket_number_increment')
|
config = Setting.get('ticket_number_increment')
|
||||||
|
|
||||||
# read counter
|
# read counter
|
||||||
min_digs = config[:min_size] || 4
|
min_digs = config[:min_size] || 4
|
||||||
counter_increment = nil
|
counter_increment = nil
|
||||||
Ticket::Counter.transaction do
|
Ticket::Counter.transaction do
|
||||||
counter = Ticket::Counter.where( generator: 'Increment' ).lock(true).first
|
counter = Ticket::Counter.where( generator: 'Increment' ).lock(true).first
|
||||||
if !counter
|
if !counter
|
||||||
counter = Ticket::Counter.new( generator: 'Increment', content: '0' )
|
counter = Ticket::Counter.new( generator: 'Increment', content: '0' )
|
||||||
end
|
end
|
||||||
counter_increment = counter.content.to_i
|
counter_increment = counter.content.to_i
|
||||||
|
|
||||||
# increase counter
|
# increase counter
|
||||||
counter_increment += 1
|
counter_increment += 1
|
||||||
|
|
||||||
# store new counter value
|
# store new counter value
|
||||||
counter.content = counter_increment.to_s
|
counter.content = counter_increment.to_s
|
||||||
counter.save
|
counter.save
|
||||||
end
|
|
||||||
|
|
||||||
# fill up number counter
|
|
||||||
if config[:checksum]
|
|
||||||
min_digs = min_digs.to_i - 1
|
|
||||||
end
|
|
||||||
fillup = Setting.get('system_id') || '1'
|
|
||||||
( 1..100 ).each do |i|
|
|
||||||
if ( fillup.length.to_i + counter_increment.to_s.length.to_i ) < min_digs.to_i
|
|
||||||
fillup = fillup + '0'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
number = fillup.to_s + counter_increment.to_s
|
|
||||||
|
|
||||||
# calculate a checksum
|
|
||||||
# The algorithm to calculate the checksum is derived from the one
|
|
||||||
# Deutsche Bundesbahn (german railway company) uses for calculation
|
|
||||||
# of the check digit of their vehikel numbering.
|
|
||||||
# The checksum is calculated by alternately multiplying the digits
|
|
||||||
# with 1 and 2 and adding the resulsts from left to right of the
|
|
||||||
# vehikel number. The modulus to 10 of this sum is substracted from
|
|
||||||
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
|
|
||||||
# (german)
|
|
||||||
if config[:checksum]
|
|
||||||
chksum = 0
|
|
||||||
mult = 1
|
|
||||||
(1..number.length).each do |i|
|
|
||||||
digit = number.to_s[i, 1]
|
|
||||||
chksum = chksum + ( mult * digit.to_i )
|
|
||||||
mult += 1
|
|
||||||
if mult == 3
|
|
||||||
mult = 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# fill up number counter
|
||||||
|
if config[:checksum]
|
||||||
|
min_digs = min_digs.to_i - 1
|
||||||
|
end
|
||||||
|
fillup = Setting.get('system_id') || '1'
|
||||||
|
( 1..100 ).each do |i|
|
||||||
|
if ( fillup.length.to_i + counter_increment.to_s.length.to_i ) < min_digs.to_i
|
||||||
|
fillup = fillup + '0'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
number = fillup.to_s + counter_increment.to_s
|
||||||
|
|
||||||
|
# calculate a checksum
|
||||||
|
# The algorithm to calculate the checksum is derived from the one
|
||||||
|
# Deutsche Bundesbahn (german railway company) uses for calculation
|
||||||
|
# of the check digit of their vehikel numbering.
|
||||||
|
# The checksum is calculated by alternately multiplying the digits
|
||||||
|
# with 1 and 2 and adding the resulsts from left to right of the
|
||||||
|
# vehikel number. The modulus to 10 of this sum is substracted from
|
||||||
|
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
|
||||||
|
# (german)
|
||||||
|
if config[:checksum]
|
||||||
|
chksum = 0
|
||||||
|
mult = 1
|
||||||
|
(1..number.length).each do |i|
|
||||||
|
digit = number.to_s[i, 1]
|
||||||
|
chksum = chksum + ( mult * digit.to_i )
|
||||||
|
mult += 1
|
||||||
|
if mult == 3
|
||||||
|
mult = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
chksum %= 10
|
||||||
|
chksum = 10 - chksum
|
||||||
|
if chksum == 10
|
||||||
|
chksum = 1
|
||||||
|
end
|
||||||
|
number += chksum.to_s
|
||||||
|
end
|
||||||
|
number
|
||||||
end
|
end
|
||||||
chksum %= 10
|
|
||||||
chksum = 10 - chksum
|
def check(string)
|
||||||
if chksum == 10
|
|
||||||
chksum = 1
|
# get config
|
||||||
|
system_id = Setting.get('system_id') || ''
|
||||||
|
ticket_hook = Setting.get('ticket_hook')
|
||||||
|
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
|
||||||
|
ticket = nil
|
||||||
|
|
||||||
|
# probe format
|
||||||
|
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,48})/i
|
||||||
|
ticket = Ticket.where( number: $1 ).first
|
||||||
|
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,48})/i
|
||||||
|
ticket = Ticket.where( number: $1 ).first
|
||||||
|
end
|
||||||
|
ticket
|
||||||
end
|
end
|
||||||
number += chksum.to_s
|
|
||||||
end
|
end
|
||||||
number
|
|
||||||
end
|
|
||||||
|
|
||||||
def check(string)
|
|
||||||
|
|
||||||
# get config
|
|
||||||
system_id = Setting.get('system_id') || ''
|
|
||||||
ticket_hook = Setting.get('ticket_hook')
|
|
||||||
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
|
|
||||||
ticket = nil
|
|
||||||
|
|
||||||
# probe format
|
|
||||||
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,48})/i then
|
|
||||||
ticket = Ticket.where( number: $1 ).first
|
|
||||||
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,48})/i then
|
|
||||||
ticket = Ticket.where( number: $1 ).first
|
|
||||||
end
|
|
||||||
ticket
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Overviews
|
class Ticket
|
||||||
|
module Overviews
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -16,24 +17,24 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.all (data)
|
def self.all (data)
|
||||||
|
|
||||||
# get customer overviews
|
# get customer overviews
|
||||||
if data[:current_user].is_role('Customer')
|
if data[:current_user].is_role('Customer')
|
||||||
role = data[:current_user].is_role( 'Customer' )
|
role = data[:current_user].is_role( 'Customer' )
|
||||||
if data[:current_user].organization_id && data[:current_user].organization.shared
|
if data[:current_user].organization_id && data[:current_user].organization.shared
|
||||||
overviews = Overview.where( role_id: role.id, active: true )
|
overviews = Overview.where( role_id: role.id, active: true )
|
||||||
else
|
else
|
||||||
overviews = Overview.where( role_id: role.id, organization_shared: false, active: true )
|
overviews = Overview.where( role_id: role.id, organization_shared: false, active: true )
|
||||||
|
end
|
||||||
|
return overviews
|
||||||
end
|
end
|
||||||
return overviews
|
|
||||||
end
|
|
||||||
|
|
||||||
# get agent overviews
|
# get agent overviews
|
||||||
role = data[:current_user].is_role( 'Agent' )
|
role = data[:current_user].is_role( 'Agent' )
|
||||||
return if !role
|
return if !role
|
||||||
Overview.where( role_id: role.id, active: true )
|
Overview.where( role_id: role.id, active: true )
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -54,197 +55,199 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.list (data)
|
def self.list (data)
|
||||||
|
|
||||||
overviews = self.all(data)
|
overviews = self.all(data)
|
||||||
return if !overviews
|
return if !overviews
|
||||||
|
|
||||||
# build up attributes hash
|
# build up attributes hash
|
||||||
overview_selected = nil
|
overview_selected = nil
|
||||||
overview_selected_raw = nil
|
overview_selected_raw = nil
|
||||||
|
|
||||||
overviews.each { |overview|
|
|
||||||
|
|
||||||
# remember selected view
|
|
||||||
if data[:view] && data[:view] == overview.link
|
|
||||||
overview_selected = overview
|
|
||||||
overview_selected_raw = Marshal.load( Marshal.dump(overview.attributes) )
|
|
||||||
end
|
|
||||||
|
|
||||||
# replace e.g. 'current_user.id' with current_user.id
|
|
||||||
overview.condition.each { |item, value |
|
|
||||||
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
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if data[:view] && !overview_selected
|
|
||||||
raise "No such view '#{ data[:view] }'"
|
|
||||||
end
|
|
||||||
|
|
||||||
# sortby
|
|
||||||
# prio
|
|
||||||
# state
|
|
||||||
# group
|
|
||||||
# customer
|
|
||||||
|
|
||||||
# order
|
|
||||||
# asc
|
|
||||||
# desc
|
|
||||||
|
|
||||||
# groupby
|
|
||||||
# prio
|
|
||||||
# state
|
|
||||||
# group
|
|
||||||
# customer
|
|
||||||
|
|
||||||
# all = attributes[:myopenassigned]
|
|
||||||
# all.merge( { :group_id => groups } )
|
|
||||||
|
|
||||||
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
|
|
||||||
# get only tickets with permissions
|
|
||||||
if data[:current_user].is_role('Customer')
|
|
||||||
group_ids = Group.select( 'groups.id' ).
|
|
||||||
where( 'groups.active = ?', true ).
|
|
||||||
map( &:id )
|
|
||||||
else
|
|
||||||
group_ids = Group.select( 'groups.id' ).joins(:users).
|
|
||||||
where( 'groups_users.user_id = ?', [ data[:current_user].id ] ).
|
|
||||||
where( 'groups.active = ?', true ).
|
|
||||||
map( &:id )
|
|
||||||
end
|
|
||||||
|
|
||||||
# overview meta for navbar
|
|
||||||
if !overview_selected
|
|
||||||
|
|
||||||
# loop each overview
|
|
||||||
result = []
|
|
||||||
overviews.each { |overview|
|
overviews.each { |overview|
|
||||||
|
|
||||||
# get count
|
# remember selected view
|
||||||
count = Ticket.where( group_id: group_ids ).where( _condition( overview.condition ) ).count()
|
if data[:view] && data[:view] == overview.link
|
||||||
|
overview_selected = overview
|
||||||
|
overview_selected_raw = Marshal.load( Marshal.dump(overview.attributes) )
|
||||||
|
end
|
||||||
|
|
||||||
# get meta info
|
# replace e.g. 'current_user.id' with current_user.id
|
||||||
all = {
|
overview.condition.each { |item, value |
|
||||||
name: overview.name,
|
if value && value.class.to_s == 'String'
|
||||||
prio: overview.prio,
|
parts = value.split( '.', 2 )
|
||||||
link: overview.link,
|
if parts[0] && parts[1] && parts[0] == 'current_user'
|
||||||
|
overview.condition[item] = data[:current_user][parts[1].to_sym]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if data[:view] && !overview_selected
|
||||||
|
raise "No such view '#{ data[:view] }'"
|
||||||
|
end
|
||||||
|
|
||||||
|
# sortby
|
||||||
|
# prio
|
||||||
|
# state
|
||||||
|
# group
|
||||||
|
# customer
|
||||||
|
|
||||||
|
# order
|
||||||
|
# asc
|
||||||
|
# desc
|
||||||
|
|
||||||
|
# groupby
|
||||||
|
# prio
|
||||||
|
# state
|
||||||
|
# group
|
||||||
|
# customer
|
||||||
|
|
||||||
|
# all = attributes[:myopenassigned]
|
||||||
|
# all.merge( { :group_id => groups } )
|
||||||
|
|
||||||
|
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
|
||||||
|
# get only tickets with permissions
|
||||||
|
if data[:current_user].is_role('Customer')
|
||||||
|
group_ids = Group.select( 'groups.id' ).
|
||||||
|
where( 'groups.active = ?', true ).
|
||||||
|
map( &:id )
|
||||||
|
else
|
||||||
|
group_ids = Group.select( 'groups.id' ).joins(:users).
|
||||||
|
where( 'groups_users.user_id = ?', [ data[:current_user].id ] ).
|
||||||
|
where( 'groups.active = ?', true ).
|
||||||
|
map( &:id )
|
||||||
|
end
|
||||||
|
|
||||||
|
# overview meta for navbar
|
||||||
|
if !overview_selected
|
||||||
|
|
||||||
|
# loop each overview
|
||||||
|
result = []
|
||||||
|
overviews.each { |overview|
|
||||||
|
|
||||||
|
# get count
|
||||||
|
count = Ticket.where( group_id: group_ids ).where( _condition( overview.condition ) ).count()
|
||||||
|
|
||||||
|
# get meta info
|
||||||
|
all = {
|
||||||
|
name: overview.name,
|
||||||
|
prio: overview.prio,
|
||||||
|
link: overview.link,
|
||||||
|
}
|
||||||
|
|
||||||
|
# push to result data
|
||||||
|
result.push all.merge( { count: count } )
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
# get result list
|
||||||
|
if data[:array]
|
||||||
|
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
|
||||||
|
tickets = Ticket.select( 'id' ).
|
||||||
|
where( group_id: group_ids ).
|
||||||
|
where( _condition( overview_selected.condition ) ).
|
||||||
|
order( order_by ).
|
||||||
|
limit( 500 )
|
||||||
|
|
||||||
|
ticket_ids = []
|
||||||
|
tickets.each { |ticket|
|
||||||
|
ticket_ids.push ticket.id
|
||||||
}
|
}
|
||||||
|
|
||||||
# push to result data
|
tickets_count = Ticket.where( group_id: group_ids ).
|
||||||
result.push all.merge( { count: count } )
|
where( _condition( overview_selected.condition ) ).
|
||||||
}
|
count()
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
# get result list
|
return {
|
||||||
if data[:array]
|
ticket_ids: ticket_ids,
|
||||||
order_by = overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s
|
tickets_count: tickets_count,
|
||||||
if overview_selected.group_by && !overview_selected.group_by.empty?
|
overview: overview_selected_raw,
|
||||||
order_by = overview_selected.group_by + '_id, ' + order_by
|
}
|
||||||
end
|
end
|
||||||
tickets = Ticket.select( 'id' ).
|
|
||||||
where( group_id: group_ids ).
|
|
||||||
where( _condition( overview_selected.condition ) ).
|
|
||||||
order( order_by ).
|
|
||||||
limit( 500 )
|
|
||||||
|
|
||||||
ticket_ids = []
|
# get tickets for overview
|
||||||
tickets.each { |ticket|
|
data[:start_page] ||= 1
|
||||||
ticket_ids.push ticket.id
|
tickets = Ticket.where( group_id: group_ids ).
|
||||||
}
|
where( _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 ) )
|
||||||
|
|
||||||
tickets_count = Ticket.where( group_id: group_ids ).
|
tickets_count = Ticket.where( group_id: group_ids ).
|
||||||
where( _condition( overview_selected.condition ) ).
|
where( _condition( overview_selected.condition ) ).
|
||||||
count()
|
count()
|
||||||
|
|
||||||
return {
|
{
|
||||||
ticket_ids: ticket_ids,
|
tickets: tickets,
|
||||||
tickets_count: tickets_count,
|
tickets_count: tickets_count,
|
||||||
overview: overview_selected_raw,
|
overview: overview_selected_raw,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# get tickets for overview
|
private
|
||||||
data[:start_page] ||= 1
|
|
||||||
tickets = Ticket.where( group_id: group_ids ).
|
|
||||||
where( _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 ) )
|
|
||||||
|
|
||||||
tickets_count = Ticket.where( group_id: group_ids ).
|
def self._condition(condition)
|
||||||
where( _condition( overview_selected.condition ) ).
|
sql = ''
|
||||||
count()
|
bind = [nil]
|
||||||
|
condition.each {|key, value|
|
||||||
{
|
if sql != ''
|
||||||
tickets: tickets,
|
sql += ' AND '
|
||||||
tickets_count: tickets_count,
|
|
||||||
overview: overview_selected_raw,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
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
|
end
|
||||||
if value['direction'] == 'last'
|
if value.class == Array
|
||||||
sql += " #{key} > ?"
|
sql += " #{key} IN (?)"
|
||||||
bind.push time
|
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
|
else
|
||||||
sql += " #{key} < ?"
|
sql += " #{key} = ?"
|
||||||
bind.push time
|
bind.push value
|
||||||
end
|
end
|
||||||
else
|
}
|
||||||
sql += " #{key} = ?"
|
bind[0] = sql
|
||||||
bind.push value
|
bind
|
||||||
end
|
end
|
||||||
}
|
|
||||||
bind[0] = sql
|
|
||||||
bind
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Permission
|
class Ticket
|
||||||
|
module Permission
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,33 +16,33 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def permission (data)
|
def permission (data)
|
||||||
|
|
||||||
# check customer
|
# check customer
|
||||||
if data[:current_user].is_role('Customer')
|
if data[:current_user].is_role('Customer')
|
||||||
|
|
||||||
# access ok if its own ticket
|
# access ok if its own ticket
|
||||||
return true if self.customer_id == data[:current_user].id
|
return true if self.customer_id == data[:current_user].id
|
||||||
|
|
||||||
# access ok if its organization ticket
|
# access ok if its organization ticket
|
||||||
if data[:current_user].organization_id && self.organization_id
|
if data[:current_user].organization_id && self.organization_id
|
||||||
return true if self.organization_id == data[:current_user].organization_id
|
return true if self.organization_id == data[:current_user].organization_id
|
||||||
|
end
|
||||||
|
|
||||||
|
# no access
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
# no access
|
# check agent
|
||||||
return false
|
|
||||||
|
# access if requestor is owner
|
||||||
|
return true if self.owner_id == data[:current_user].id
|
||||||
|
|
||||||
|
# access if requestor is in group
|
||||||
|
data[:current_user].groups.each {|group|
|
||||||
|
return true if self.group.id == group.id
|
||||||
|
}
|
||||||
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
# check agent
|
|
||||||
|
|
||||||
# access if requestor is owner
|
|
||||||
return true if self.owner_id == data[:current_user].id
|
|
||||||
|
|
||||||
# access if requestor is in group
|
|
||||||
data[:current_user].groups.each {|group|
|
|
||||||
return true if self.group.id == group.id
|
|
||||||
}
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::Priority < ApplicationModel
|
class Ticket
|
||||||
self.table_name = 'ticket_priorities'
|
class Priority < ApplicationModel
|
||||||
validates :name, presence: true
|
self.table_name = 'ticket_priorities'
|
||||||
|
validates :name, presence: true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::ScreenOptions
|
class Ticket
|
||||||
|
module ScreenOptions
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -14,9 +15,9 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.agents
|
def self.agents
|
||||||
User.where( active: true ).joins(:roles).where( 'roles.name' => 'Agent', 'roles.active' => true ).uniq()
|
User.where( active: true ).joins(:roles).where( 'roles.name' => 'Agent', 'roles.active' => true ).uniq()
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -42,83 +43,83 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.attributes_to_change(params)
|
def self.attributes_to_change(params)
|
||||||
if params[:ticket_id]
|
if params[:ticket_id]
|
||||||
params[:ticket] = Ticket.find( params[:ticket_id] )
|
params[:ticket] = Ticket.find( params[:ticket_id] )
|
||||||
end
|
|
||||||
if params[:article_id]
|
|
||||||
params[:article] = Ticket::Article.find( params[:article_id] )
|
|
||||||
end
|
|
||||||
|
|
||||||
filter = {}
|
|
||||||
assets = {}
|
|
||||||
|
|
||||||
# get ticket states
|
|
||||||
state_ids = []
|
|
||||||
if params[:ticket]
|
|
||||||
state_type = params[:ticket].state.state_type
|
|
||||||
end
|
|
||||||
state_types = ['open', 'closed', 'pending action', 'pending reminder']
|
|
||||||
if state_type && !state_types.include?(state_type.name)
|
|
||||||
state_ids.push params[:ticket].state.id
|
|
||||||
end
|
|
||||||
state_types.each {|type|
|
|
||||||
state_type = Ticket::StateType.where( name: type ).first
|
|
||||||
if state_type
|
|
||||||
state_type.states.each {|state|
|
|
||||||
assets = state.assets(assets)
|
|
||||||
state_ids.push state.id
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
}
|
if params[:article_id]
|
||||||
filter[:state_id] = state_ids
|
params[:article] = Ticket::Article.find( params[:article_id] )
|
||||||
|
|
||||||
# get priorities
|
|
||||||
priority_ids = []
|
|
||||||
Ticket::Priority.where( active: true ).each { |priority|
|
|
||||||
assets = priority.assets(assets)
|
|
||||||
priority_ids.push priority.id
|
|
||||||
}
|
|
||||||
filter[:priority_id] = priority_ids
|
|
||||||
|
|
||||||
type_ids = []
|
|
||||||
if params[:ticket]
|
|
||||||
types = ['note', 'phone']
|
|
||||||
if params[:ticket].group.email_address_id
|
|
||||||
types.push 'email'
|
|
||||||
end
|
end
|
||||||
types.each {|type_name|
|
|
||||||
type = Ticket::Article::Type.lookup( name: type_name )
|
filter = {}
|
||||||
if type
|
assets = {}
|
||||||
type_ids.push type.id
|
|
||||||
|
# get ticket states
|
||||||
|
state_ids = []
|
||||||
|
if params[:ticket]
|
||||||
|
state_type = params[:ticket].state.state_type
|
||||||
|
end
|
||||||
|
state_types = ['open', 'closed', 'pending action', 'pending reminder']
|
||||||
|
if state_type && !state_types.include?(state_type.name)
|
||||||
|
state_ids.push params[:ticket].state.id
|
||||||
|
end
|
||||||
|
state_types.each {|type|
|
||||||
|
state_type = Ticket::StateType.where( name: type ).first
|
||||||
|
if state_type
|
||||||
|
state_type.states.each {|state|
|
||||||
|
assets = state.assets(assets)
|
||||||
|
state_ids.push state.id
|
||||||
|
}
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
end
|
filter[:state_id] = state_ids
|
||||||
filter[:type_id] = type_ids
|
|
||||||
|
|
||||||
# get group / user relations
|
# get priorities
|
||||||
agents = {}
|
priority_ids = []
|
||||||
Ticket::ScreenOptions.agents.each { |user|
|
Ticket::Priority.where( active: true ).each { |priority|
|
||||||
agents[ user.id ] = 1
|
assets = priority.assets(assets)
|
||||||
}
|
priority_ids.push priority.id
|
||||||
|
|
||||||
dependencies = { group_id: { '' => { owner_id: [] } } }
|
|
||||||
Group.where( active: true ).each { |group|
|
|
||||||
assets = group.assets(assets)
|
|
||||||
dependencies[:group_id][group.id] = { owner_id: [] }
|
|
||||||
group.users.each {|user|
|
|
||||||
next if !agents[ user.id ]
|
|
||||||
assets = user.assets(assets)
|
|
||||||
dependencies[:group_id][ group.id ][ :owner_id ].push user.id
|
|
||||||
}
|
}
|
||||||
}
|
filter[:priority_id] = priority_ids
|
||||||
|
|
||||||
{
|
type_ids = []
|
||||||
assets: assets,
|
if params[:ticket]
|
||||||
filter: filter,
|
types = ['note', 'phone']
|
||||||
dependencies: dependencies,
|
if params[:ticket].group.email_address_id
|
||||||
}
|
types.push 'email'
|
||||||
end
|
end
|
||||||
|
types.each {|type_name|
|
||||||
|
type = Ticket::Article::Type.lookup( name: type_name )
|
||||||
|
if type
|
||||||
|
type_ids.push type.id
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
filter[:type_id] = type_ids
|
||||||
|
|
||||||
|
# get group / user relations
|
||||||
|
agents = {}
|
||||||
|
Ticket::ScreenOptions.agents.each { |user|
|
||||||
|
agents[ user.id ] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies = { group_id: { '' => { owner_id: [] } } }
|
||||||
|
Group.where( active: true ).each { |group|
|
||||||
|
assets = group.assets(assets)
|
||||||
|
dependencies[:group_id][group.id] = { owner_id: [] }
|
||||||
|
group.users.each {|user|
|
||||||
|
next if !agents[ user.id ]
|
||||||
|
assets = user.assets(assets)
|
||||||
|
dependencies[:group_id][ group.id ][ :owner_id ].push user.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
assets: assets,
|
||||||
|
filter: filter,
|
||||||
|
dependencies: dependencies,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -139,39 +140,39 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.list_by_customer(data)
|
def self.list_by_customer(data)
|
||||||
|
|
||||||
# get closed/open states
|
# get closed/open states
|
||||||
state_list_open = Ticket::State.by_category( 'open' )
|
state_list_open = Ticket::State.by_category( 'open' )
|
||||||
state_list_closed = Ticket::State.by_category( 'closed' )
|
state_list_closed = Ticket::State.by_category( 'closed' )
|
||||||
|
|
||||||
# get tickets
|
# get tickets
|
||||||
tickets_open = Ticket.where(
|
tickets_open = Ticket.where(
|
||||||
customer_id: data[:customer_id],
|
customer_id: data[:customer_id],
|
||||||
state_id: state_list_open
|
state_id: state_list_open
|
||||||
).limit( data[:limit] || 15 ).order('created_at DESC')
|
).limit( data[:limit] || 15 ).order('created_at DESC')
|
||||||
assets = {}
|
assets = {}
|
||||||
ticket_ids_open = []
|
ticket_ids_open = []
|
||||||
tickets_open.each {|ticket|
|
tickets_open.each {|ticket|
|
||||||
ticket_ids_open.push ticket.id
|
ticket_ids_open.push ticket.id
|
||||||
assets = ticket.assets(assets)
|
assets = ticket.assets(assets)
|
||||||
}
|
}
|
||||||
|
|
||||||
tickets_closed = Ticket.where(
|
tickets_closed = Ticket.where(
|
||||||
customer_id: data[:customer_id],
|
customer_id: data[:customer_id],
|
||||||
state_id: state_list_closed
|
state_id: state_list_closed
|
||||||
).limit( data[:limit] || 15 ).order('created_at DESC')
|
).limit( data[:limit] || 15 ).order('created_at DESC')
|
||||||
ticket_ids_closed = []
|
ticket_ids_closed = []
|
||||||
tickets_closed.each {|ticket|
|
tickets_closed.each {|ticket|
|
||||||
ticket_ids_closed.push ticket.id
|
ticket_ids_closed.push ticket.id
|
||||||
assets = ticket.assets(assets)
|
assets = ticket.assets(assets)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ticket_ids_open: ticket_ids_open,
|
ticket_ids_open: ticket_ids_open,
|
||||||
ticket_ids_closed: ticket_ids_closed,
|
ticket_ids_closed: ticket_ids_closed,
|
||||||
assets: assets,
|
assets: assets,
|
||||||
}
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Search
|
class Ticket
|
||||||
|
module Search
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -45,102 +46,102 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def search (params)
|
def search (params)
|
||||||
|
|
||||||
# get params
|
# get params
|
||||||
query = params[:query]
|
query = params[:query]
|
||||||
limit = params[:limit] || 12
|
limit = params[:limit] || 12
|
||||||
current_user = params[:current_user]
|
current_user = params[:current_user]
|
||||||
full = false
|
full = false
|
||||||
if params[:full] || !params.key?(:full)
|
if params[:full] || !params.key?(:full)
|
||||||
full = true
|
full = true
|
||||||
end
|
|
||||||
|
|
||||||
# try search index backend
|
|
||||||
if !params[:detail] && SearchIndexBackend.enabled?
|
|
||||||
query_extention = {}
|
|
||||||
query_extention['bool'] = {}
|
|
||||||
query_extention['bool']['must'] = []
|
|
||||||
|
|
||||||
if current_user.is_role('Agent')
|
|
||||||
groups = Group.joins(:users).
|
|
||||||
where( 'groups_users.user_id = ?', current_user.id ).
|
|
||||||
where( 'groups.active = ?', true )
|
|
||||||
group_condition = []
|
|
||||||
groups.each {|group|
|
|
||||||
group_condition.push group.name
|
|
||||||
}
|
|
||||||
access_condition = {
|
|
||||||
'query_string' => { 'default_field' => 'Ticket.group.name', 'query' => "\"#{group_condition.join('" OR "')}\"" }
|
|
||||||
}
|
|
||||||
query_extention['bool']['must'].push access_condition
|
|
||||||
else
|
|
||||||
if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false )
|
|
||||||
access_condition = {
|
|
||||||
'query_string' => { 'default_field' => 'Ticket.customer_id', 'query' => current_user.id }
|
|
||||||
}
|
|
||||||
# customer_id: XXX
|
|
||||||
# conditions = [ 'customer_id = ?', current_user.id ]
|
|
||||||
else
|
|
||||||
access_condition = {
|
|
||||||
'query_string' => { 'query' => "Ticket.customer_id:#{current_user.id} OR Ticket.organization_id:#{current_user.organization.id}" }
|
|
||||||
}
|
|
||||||
# customer_id: XXX OR organization_id: XXX
|
|
||||||
# conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ]
|
|
||||||
end
|
|
||||||
query_extention['bool']['must'].push access_condition
|
|
||||||
end
|
end
|
||||||
|
|
||||||
items = SearchIndexBackend.search( query, limit, 'Ticket', query_extention )
|
# try search index backend
|
||||||
|
if !params[:detail] && SearchIndexBackend.enabled?
|
||||||
|
query_extention = {}
|
||||||
|
query_extention['bool'] = {}
|
||||||
|
query_extention['bool']['must'] = []
|
||||||
|
|
||||||
|
if current_user.is_role('Agent')
|
||||||
|
groups = Group.joins(:users)
|
||||||
|
.where( 'groups_users.user_id = ?', current_user.id )
|
||||||
|
.where( 'groups.active = ?', true )
|
||||||
|
group_condition = []
|
||||||
|
groups.each {|group|
|
||||||
|
group_condition.push group.name
|
||||||
|
}
|
||||||
|
access_condition = {
|
||||||
|
'query_string' => { 'default_field' => 'Ticket.group.name', 'query' => "\"#{group_condition.join('" OR "')}\"" }
|
||||||
|
}
|
||||||
|
query_extention['bool']['must'].push access_condition
|
||||||
|
else
|
||||||
|
if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false )
|
||||||
|
access_condition = {
|
||||||
|
'query_string' => { 'default_field' => 'Ticket.customer_id', 'query' => current_user.id }
|
||||||
|
}
|
||||||
|
# customer_id: XXX
|
||||||
|
# conditions = [ 'customer_id = ?', current_user.id ]
|
||||||
|
else
|
||||||
|
access_condition = {
|
||||||
|
'query_string' => { 'query' => "Ticket.customer_id:#{current_user.id} OR Ticket.organization_id:#{current_user.organization.id}" }
|
||||||
|
}
|
||||||
|
# customer_id: XXX OR organization_id: XXX
|
||||||
|
# conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ]
|
||||||
|
end
|
||||||
|
query_extention['bool']['must'].push access_condition
|
||||||
|
end
|
||||||
|
|
||||||
|
items = SearchIndexBackend.search( query, limit, 'Ticket', query_extention )
|
||||||
|
if !full
|
||||||
|
ids = []
|
||||||
|
items.each {|item|
|
||||||
|
ids.push item[:id]
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
end
|
||||||
|
tickets = []
|
||||||
|
items.each { |item|
|
||||||
|
tickets.push Ticket.lookup( id: item[:id] )
|
||||||
|
}
|
||||||
|
return tickets
|
||||||
|
end
|
||||||
|
|
||||||
|
# fallback do sql query
|
||||||
|
access_condition = Ticket.access_condition( current_user )
|
||||||
|
|
||||||
|
# do query
|
||||||
|
# - stip out * we already search for *query* -
|
||||||
|
if query
|
||||||
|
query.gsub! '*', ''
|
||||||
|
tickets_all = Ticket.select('DISTINCT(tickets.id)')
|
||||||
|
.where(access_condition)
|
||||||
|
.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)
|
||||||
|
.order('`tickets`.`created_at` DESC')
|
||||||
|
.limit(limit)
|
||||||
|
else
|
||||||
|
tickets_all = Ticket.select('DISTINCT(tickets.id)')
|
||||||
|
.where(access_condition)
|
||||||
|
.where(params[:condition])
|
||||||
|
.order('`tickets`.`created_at` DESC')
|
||||||
|
.limit(limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
# build result list
|
||||||
if !full
|
if !full
|
||||||
ids = []
|
ids = []
|
||||||
items.each {|item|
|
tickets_all.each { |ticket|
|
||||||
ids.push item[:id]
|
ids.push ticket.id
|
||||||
}
|
}
|
||||||
return ids
|
return ids
|
||||||
end
|
end
|
||||||
|
|
||||||
tickets = []
|
tickets = []
|
||||||
items.each { |item|
|
|
||||||
tickets.push Ticket.lookup( id: item[:id] )
|
|
||||||
}
|
|
||||||
return tickets
|
|
||||||
end
|
|
||||||
|
|
||||||
# fallback do sql query
|
|
||||||
access_condition = Ticket.access_condition( current_user )
|
|
||||||
|
|
||||||
# do query
|
|
||||||
# - stip out * we already search for *query* -
|
|
||||||
if query
|
|
||||||
query.gsub! '*', ''
|
|
||||||
tickets_all = Ticket.select('DISTINCT(tickets.id)').
|
|
||||||
where(access_condition).
|
|
||||||
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).
|
|
||||||
order('`tickets`.`created_at` DESC').
|
|
||||||
limit(limit)
|
|
||||||
else
|
|
||||||
tickets_all = Ticket.select('DISTINCT(tickets.id)').
|
|
||||||
where(access_condition).
|
|
||||||
where(params[:condition]).
|
|
||||||
order('`tickets`.`created_at` DESC').
|
|
||||||
limit(limit)
|
|
||||||
end
|
|
||||||
|
|
||||||
# build result list
|
|
||||||
if !full
|
|
||||||
ids = []
|
|
||||||
tickets_all.each { |ticket|
|
tickets_all.each { |ticket|
|
||||||
ids.push ticket.id
|
tickets.push Ticket.lookup( id: ticket.id )
|
||||||
}
|
}
|
||||||
return ids
|
tickets
|
||||||
end
|
end
|
||||||
|
|
||||||
tickets = []
|
|
||||||
tickets_all.each { |ticket|
|
|
||||||
tickets.push Ticket.lookup( id: ticket.id )
|
|
||||||
}
|
|
||||||
tickets
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::SearchIndex
|
class Ticket
|
||||||
|
module SearchIndex
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,95 +16,95 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def search_index_update_backend
|
def search_index_update_backend
|
||||||
return if !self.class.search_index_support_config
|
return if !self.class.search_index_support_config
|
||||||
|
|
||||||
# default ignored attributes
|
# default ignored attributes
|
||||||
ignore_attributes = {
|
ignore_attributes = {
|
||||||
created_by_id: true,
|
created_by_id: true,
|
||||||
updated_by_id: true,
|
updated_by_id: true,
|
||||||
active: true,
|
active: true,
|
||||||
}
|
|
||||||
if self.class.search_index_support_config[:ignore_attributes]
|
|
||||||
self.class.search_index_support_config[:ignore_attributes].each {|key, value|
|
|
||||||
ignore_attributes[key] = value
|
|
||||||
}
|
}
|
||||||
end
|
if self.class.search_index_support_config[:ignore_attributes]
|
||||||
|
self.class.search_index_support_config[:ignore_attributes].each {|key, value|
|
||||||
# for performance reasons, Model.search_index_reload will only collect if of object
|
ignore_attributes[key] = value
|
||||||
# get whole data here
|
}
|
||||||
ticket = self.class.find(self.id)
|
|
||||||
|
|
||||||
# remove ignored attributes
|
|
||||||
attributes = ticket.attributes
|
|
||||||
ignore_attributes.each {|key, value|
|
|
||||||
next if value != true
|
|
||||||
attributes.delete( key.to_s )
|
|
||||||
}
|
|
||||||
|
|
||||||
# add tags
|
|
||||||
tags = Tag.tag_list( object: 'Ticket', o_id: self.id )
|
|
||||||
if tags && !tags.empty?
|
|
||||||
attributes[:tag] = tags
|
|
||||||
end
|
|
||||||
|
|
||||||
# lookup attributes of ref. objects (normally name and note)
|
|
||||||
attributes = search_index_attribute_lookup( attributes, ticket )
|
|
||||||
|
|
||||||
# list ignored file extentions
|
|
||||||
attachments_ignore = Setting.get('es_attachment_ignore') || [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe' ]
|
|
||||||
|
|
||||||
# max attachment size
|
|
||||||
attachment_max_size_in_mb = Setting.get('es_attachment_max_size_in_mb') || 40
|
|
||||||
|
|
||||||
# collect article data
|
|
||||||
articles = Ticket::Article.where( ticket_id: self.id )
|
|
||||||
attributes['articles'] = []
|
|
||||||
articles.each {|article|
|
|
||||||
article_attributes = article.attributes
|
|
||||||
|
|
||||||
# remove note needed attributes
|
|
||||||
ignore = ['created_by_id', 'updated_by_id', 'updated_at', 'references', 'message_id_md5', 'message_id', 'in_reply_to', 'ticket_id']
|
|
||||||
ignore.each {|attribute|
|
|
||||||
article_attributes.delete( attribute )
|
|
||||||
}
|
|
||||||
|
|
||||||
# lookup attributes of ref. objects (normally name and note)
|
|
||||||
article_attributes = search_index_attribute_lookup( article_attributes, article )
|
|
||||||
|
|
||||||
# index raw text body
|
|
||||||
if article_attributes['content_type'] && article_attributes['content_type'] == 'text/html' && article_attributes['body']
|
|
||||||
article_attributes['body'] = article_attributes['body'].html2text
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# lookup attachments
|
# for performance reasons, Model.search_index_reload will only collect if of object
|
||||||
article.attachments.each {|attachment|
|
# get whole data here
|
||||||
if !article_attributes['attachments']
|
ticket = self.class.find(self.id)
|
||||||
article_attributes['attachments'] = []
|
|
||||||
|
# remove ignored attributes
|
||||||
|
attributes = ticket.attributes
|
||||||
|
ignore_attributes.each {|key, value|
|
||||||
|
next if value != true
|
||||||
|
attributes.delete( key.to_s )
|
||||||
|
}
|
||||||
|
|
||||||
|
# add tags
|
||||||
|
tags = Tag.tag_list( object: 'Ticket', o_id: self.id )
|
||||||
|
if tags && !tags.empty?
|
||||||
|
attributes[:tag] = tags
|
||||||
|
end
|
||||||
|
|
||||||
|
# lookup attributes of ref. objects (normally name and note)
|
||||||
|
attributes = search_index_attribute_lookup( attributes, ticket )
|
||||||
|
|
||||||
|
# list ignored file extentions
|
||||||
|
attachments_ignore = Setting.get('es_attachment_ignore') || [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe' ]
|
||||||
|
|
||||||
|
# max attachment size
|
||||||
|
attachment_max_size_in_mb = Setting.get('es_attachment_max_size_in_mb') || 40
|
||||||
|
|
||||||
|
# collect article data
|
||||||
|
articles = Ticket::Article.where( ticket_id: self.id )
|
||||||
|
attributes['articles'] = []
|
||||||
|
articles.each {|article|
|
||||||
|
article_attributes = article.attributes
|
||||||
|
|
||||||
|
# remove note needed attributes
|
||||||
|
ignore = ['created_by_id', 'updated_by_id', 'updated_at', 'references', 'message_id_md5', 'message_id', 'in_reply_to', 'ticket_id']
|
||||||
|
ignore.each {|attribute|
|
||||||
|
article_attributes.delete( attribute )
|
||||||
|
}
|
||||||
|
|
||||||
|
# lookup attributes of ref. objects (normally name and note)
|
||||||
|
article_attributes = search_index_attribute_lookup( article_attributes, article )
|
||||||
|
|
||||||
|
# index raw text body
|
||||||
|
if article_attributes['content_type'] && article_attributes['content_type'] == 'text/html' && article_attributes['body']
|
||||||
|
article_attributes['body'] = article_attributes['body'].html2text
|
||||||
end
|
end
|
||||||
|
|
||||||
# check file size
|
# lookup attachments
|
||||||
if attachment.content && attachment.content.size / 1024 <= attachment_max_size_in_mb * 1024
|
article.attachments.each {|attachment|
|
||||||
|
if !article_attributes['attachments']
|
||||||
|
article_attributes['attachments'] = []
|
||||||
|
end
|
||||||
|
|
||||||
# check ignored files
|
# check file size
|
||||||
if attachment.filename
|
if attachment.content && attachment.content.size / 1024 <= attachment_max_size_in_mb * 1024
|
||||||
filename_extention = attachment.filename.downcase
|
|
||||||
filename_extention.gsub!(/^.*(\..+?)$/, '\\1')
|
# check ignored files
|
||||||
if !attachments_ignore.include?( filename_extention.downcase )
|
if attachment.filename
|
||||||
data = {
|
filename_extention = attachment.filename.downcase
|
||||||
'_name' => attachment.filename,
|
filename_extention.gsub!(/^.*(\..+?)$/, '\\1')
|
||||||
'_content' => Base64.encode64( attachment.content )
|
if !attachments_ignore.include?( filename_extention.downcase )
|
||||||
}
|
data = {
|
||||||
article_attributes['attachments'].push data
|
'_name' => attachment.filename,
|
||||||
|
'_content' => Base64.encode64( attachment.content )
|
||||||
|
}
|
||||||
|
article_attributes['attachments'].push data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
}
|
||||||
|
attributes['articles'].push article_attributes
|
||||||
}
|
}
|
||||||
attributes['articles'].push article_attributes
|
|
||||||
}
|
|
||||||
|
|
||||||
return if !attributes
|
return if !attributes
|
||||||
SearchIndexBackend.add(self.class.to_s, attributes)
|
SearchIndexBackend.add(self.class.to_s, attributes)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::State < ApplicationModel
|
class Ticket
|
||||||
belongs_to :state_type, class_name: 'Ticket::StateType'
|
class State < ApplicationModel
|
||||||
validates :name, presence: true
|
belongs_to :state_type, class_name: 'Ticket::StateType'
|
||||||
|
validates :name, presence: true
|
||||||
|
|
||||||
latest_change_support
|
latest_change_support
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -18,18 +19,18 @@ returns:
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.by_category(category)
|
def self.by_category(category)
|
||||||
if category == 'open'
|
if category == 'open'
|
||||||
return Ticket::State.where(
|
return Ticket::State.where(
|
||||||
state_type_id: Ticket::StateType.where( name: ['new', 'open', 'pending reminder', 'pending action'] )
|
state_type_id: Ticket::StateType.where( name: ['new', 'open', 'pending reminder', 'pending action'] )
|
||||||
)
|
)
|
||||||
elsif category == 'closed'
|
elsif category == 'closed'
|
||||||
return Ticket::State.where(
|
return Ticket::State.where(
|
||||||
state_type_id: Ticket::StateType.where( name: ['closed'] )
|
state_type_id: Ticket::StateType.where( name: ['closed'] )
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
raise "Unknown category '#{category}'"
|
||||||
end
|
end
|
||||||
raise "Unknown category '#{category}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -45,9 +46,10 @@ returns:
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def ignore_escalation?
|
def ignore_escalation?
|
||||||
ignore_escalation = ['removed', 'closed', 'merged']
|
ignore_escalation = ['removed', 'closed', 'merged']
|
||||||
return true if ignore_escalation.include?( self.name )
|
return true if ignore_escalation.include?( self.name )
|
||||||
false
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
class Ticket::StateType < ApplicationModel
|
class Ticket
|
||||||
has_many :states, class_name: 'Ticket::State'
|
class StateType < ApplicationModel
|
||||||
validates :name, presence: true
|
has_many :states, class_name: 'Ticket::State'
|
||||||
latest_change_support
|
validates :name, presence: true
|
||||||
|
latest_change_support
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
module Ticket::Subject
|
class Ticket
|
||||||
|
module Subject
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
@ -15,28 +16,28 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def subject_build (subject)
|
def subject_build (subject)
|
||||||
|
|
||||||
# clena subject
|
# clena subject
|
||||||
subject = self.subject_clean(subject)
|
subject = self.subject_clean(subject)
|
||||||
|
|
||||||
ticket_hook = Setting.get('ticket_hook')
|
ticket_hook = Setting.get('ticket_hook')
|
||||||
ticket_hook_divider = Setting.get('ticket_hook_divider')
|
ticket_hook_divider = Setting.get('ticket_hook_divider')
|
||||||
|
|
||||||
# none position
|
# none position
|
||||||
if Setting.get('ticket_hook_position') == 'none'
|
if Setting.get('ticket_hook_position') == 'none'
|
||||||
return subject
|
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
|
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
|
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
clean subject remove ticket number and other not needed chars
|
clean subject remove ticket number and other not needed chars
|
||||||
|
@ -50,29 +51,30 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def subject_clean (subject)
|
def subject_clean (subject)
|
||||||
ticket_hook = Setting.get('ticket_hook')
|
ticket_hook = Setting.get('ticket_hook')
|
||||||
ticket_hook_divider = Setting.get('ticket_hook_divider')
|
ticket_hook_divider = Setting.get('ticket_hook_divider')
|
||||||
ticket_subject_size = Setting.get('ticket_subject_size')
|
ticket_subject_size = Setting.get('ticket_subject_size')
|
||||||
|
|
||||||
# remove all possible ticket hook formats with []
|
# 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}:#{self.number}\](\s+?|)/, ''
|
subject = subject.gsub /\[#{ticket_hook}:#{self.number}\](\s+?|)/, ''
|
||||||
subject = subject.gsub /\[#{ticket_hook}#{ticket_hook_divider}#{self.number}\](\s+?|)/, ''
|
subject = subject.gsub /\[#{ticket_hook}#{ticket_hook_divider}#{self.number}\](\s+?|)/, ''
|
||||||
|
|
||||||
# remove all possible ticket hook formats without []
|
# 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}:#{self.number}(\s+?|)/, ''
|
subject = subject.gsub /#{ticket_hook}:#{self.number}(\s+?|)/, ''
|
||||||
subject = subject.gsub /#{ticket_hook}#{ticket_hook_divider}#{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]: "
|
# remove leading "..:\s" and "..[\d+]:\s" e. g. "Re: " or "Re[5]: "
|
||||||
subject = subject.gsub /^(..(\[\d+\])?:\s)+/, ''
|
subject = subject.gsub /^(..(\[\d+\])?:\s)+/, ''
|
||||||
|
|
||||||
# resize subject based on config
|
# resize subject based on config
|
||||||
if subject.length > ticket_subject_size.to_i
|
if subject.length > ticket_subject_size.to_i
|
||||||
subject = subject[ 0, ticket_subject_size.to_i ] + '[...]'
|
subject = subject[ 0, ticket_subject_size.to_i ] + '[...]'
|
||||||
|
end
|
||||||
|
|
||||||
|
subject
|
||||||
end
|
end
|
||||||
|
|
||||||
subject
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -75,11 +75,10 @@ returns
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
['created_by_id', 'updated_by_id'].each {|item|
|
['created_by_id', 'updated_by_id'].each {|item|
|
||||||
if self[ item ]
|
next if !self[ item ]
|
||||||
if !data[ User.to_app_model ][ self[ item ] ]
|
if !data[ User.to_app_model ][ self[ item ] ]
|
||||||
user = User.lookup( id: self[ item ] )
|
user = User.lookup( id: self[ item ] )
|
||||||
data = user.assets( data )
|
data = user.assets( data )
|
||||||
end
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
|
|
Loading…
Reference in a new issue