trabajo-afectivo/app/models/ticket.rb

405 lines
11 KiB
Ruby
Raw Normal View History

2014-02-03 19:23:00 +00:00
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
2012-07-29 20:25:31 +00:00
class Ticket < ApplicationModel
2013-09-29 21:37:49 +00:00
include Ticket::Escalation
include Ticket::Subject
include Ticket::Permission
load 'ticket/assets.rb'
2013-09-29 21:37:49 +00:00
include Ticket::Assets
load 'ticket/history_log.rb'
2013-09-29 21:37:49 +00:00
include Ticket::HistoryLog
load 'ticket/activity_stream_log.rb'
2013-09-29 21:37:49 +00:00
include Ticket::ActivityStreamLog
load 'ticket/search_index.rb'
include Ticket::SearchIndex
2013-09-29 21:37:49 +00:00
extend Ticket::Search
before_create :check_generate, :check_defaults, :check_title
before_update :check_defaults, :check_title, :reset_pending_time
before_destroy :destroy_dependencies
notify_clients_support
2013-09-29 16:40:42 +00:00
latest_change_support
activity_stream_support ignore_attributes: {
create_article_type_id: true,
create_article_sender_id: true,
article_count: true,
first_response: true,
first_response_escal_date: true,
first_response_sla_time: true,
first_response_in_min: true,
first_response_diff_in_min: true,
close_time: true,
close_time_escal_date: true,
close_time_sla_time: true,
close_time_in_min: true,
close_time_diff_in_min: true,
update_time_escal_date: true,
updtate_time_sla_time: true,
update_time_in_min: true,
update_time_diff_in_min: true,
last_contact: true,
last_contact_agent: true,
last_contact_customer: true,
2013-10-05 12:56:03 +00:00
}
2013-09-29 21:37:49 +00:00
history_support ignore_attributes: {
create_article_type_id: true,
create_article_sender_id: true,
article_count: true,
2013-09-29 21:37:49 +00:00
}
2014-02-02 18:58:31 +00:00
search_index_support(
ignore_attributes: {
create_article_type_id: true,
create_article_sender_id: true,
article_count: true,
2014-02-02 18:58:31 +00:00
},
keep_attributes: {
customer_id: true,
organization_id: true,
2014-02-02 18:58:31 +00:00
},
)
2012-04-16 08:04:49 +00:00
belongs_to :group
has_many :articles, class_name: 'Ticket::Article', after_add: :cache_update, after_remove: :cache_update
belongs_to :organization
belongs_to :state, class_name: 'Ticket::State'
belongs_to :priority, class_name: 'Ticket::Priority'
belongs_to :owner, class_name: 'User'
belongs_to :customer, class_name: 'User'
belongs_to :created_by, class_name: 'User'
belongs_to :updated_by, class_name: 'User'
belongs_to :create_article_type, class_name: 'Ticket::Article::Type'
belongs_to :create_article_sender, class_name: 'Ticket::Article::Sender'
2012-04-10 14:06:46 +00:00
2014-09-09 23:42:20 +00:00
self.inheritance_column = nil
attr_accessor :callback_loop
=begin
2013-08-17 21:13:34 +00:00
list of agents in group of ticket
ticket = Ticket.find(123)
2013-08-17 21:13:34 +00:00
result = ticket.agent_of_group
returns
2013-08-17 21:13:34 +00:00
result = [user1, user2, ...]
=end
2012-04-10 14:06:46 +00:00
def agent_of_group
Group.find( group_id ).users.where( active: true ).joins(:roles).where( 'roles.name' => Z_ROLENAME_AGENT, 'roles.active' => true ).uniq()
2012-04-10 14:06:46 +00:00
end
=begin
2014-11-10 07:34:20 +00:00
get user access conditions
2015-02-15 09:23:55 +00:00
conditions = Ticket.access_condition( User.find(1) )
2014-11-10 07:34:20 +00:00
returns
result = [user1, user2, ...]
=end
def self.access_condition(user)
access_condition = []
if user.role?(Z_ROLENAME_AGENT)
group_ids = Group.select( 'groups.id' ).joins(:users)
.where( 'groups_users.user_id = ?', user.id )
.where( 'groups.active = ?', true )
.map( &:id )
2014-11-10 07:34:20 +00:00
access_condition = [ 'group_id IN (?)', group_ids ]
else
if !user.organization || ( !user.organization.shared || user.organization.shared == false )
access_condition = [ 'customer_id = ?', user.id ]
else
access_condition = [ '( customer_id = ? OR organization_id = ? )', user.id, user.organization.id ]
end
end
access_condition
end
=begin
2015-05-21 14:40:04 +00:00
processes tickets which have reached their pending time and sets next state_id
processed_tickets = Ticket.process_pending()
returns
processed_tickets = [<Ticket>, ...]
=end
def self.process_pending
ticket_states = Ticket::State.where(
state_type_id: Ticket::StateType.find_by( name: 'pending action' ),
)
.where.not(next_state_id: nil) # rubocop:disable Style/MultilineOperationIndentation
return [] if !ticket_states
next_state_map = {}
ticket_states.each { |state|
next_state_map[state.id] = state.next_state_id
}
tickets = where(
state_id: next_state_map.keys,
)
.where( 'pending_time <= ?', Time.zone.now ) # rubocop:disable Style/MultilineOperationIndentation
return [] if !tickets
result = []
tickets.each { |ticket|
ticket.state_id = next_state_map[ticket.state_id]
ticket.updated_at = Time.zone.now
ticket.updated_by_id = 1
ticket.save!
result.push ticket
}
# we do not have an destructor at this point, so we need to
# execute ticket events manually
Observer::Ticket::Notification.transaction
2015-05-21 14:40:04 +00:00
result
end
=begin
merge tickets
ticket = Ticket.find(123)
result = ticket.merge_to(
ticket_id: 123,
user_id: 123,
)
returns
result = true|false
=end
2012-07-03 13:24:31 +00:00
def merge_to(data)
2012-11-07 23:47:05 +00:00
2012-07-03 13:24:31 +00:00
# update articles
Ticket::Article.where( ticket_id: id ).each(&:touch)
# quiet update of reassign of articles
Ticket::Article.where( ticket_id: id ).update_all( ['ticket_id = ?', data[:ticket_id] ] )
2012-11-07 23:47:05 +00:00
# touch new ticket (to broadcast change)
Ticket.find( data[:ticket_id] ).touch
2012-07-03 13:24:31 +00:00
# update history
2012-11-07 23:47:05 +00:00
2012-07-03 13:24:31 +00:00
# create new merge article
Ticket::Article.create(
ticket_id: id,
type_id: Ticket::Article::Type.lookup( name: 'note' ).id,
sender_id: Ticket::Article::Sender.lookup( name: Z_ROLENAME_AGENT ).id,
body: 'merged',
internal: false,
created_by_id: data[:user_id],
updated_by_id: data[:user_id],
2012-07-03 13:24:31 +00:00
)
# add history to both
# link tickets
2012-08-21 10:28:41 +00:00
Link.add(
link_type: 'parent',
link_object_source: 'Ticket',
link_object_source_value: data[:ticket_id],
link_object_target: 'Ticket',
link_object_target_value: id
2012-08-21 10:28:41 +00:00
)
2012-07-03 13:24:31 +00:00
# set state to 'merged'
self.state_id = Ticket::State.lookup( name: 'merged' ).id
2012-07-03 13:24:31 +00:00
# rest owner
self.owner_id = User.find_by( login: '-' ).id
2012-07-03 13:24:31 +00:00
# save ticket
save
end
=begin
check if online notifcation should be shown in general as already seen with current state
ticket = Ticket.find(1)
seen = ticket.online_notification_seen_state(user_id_check)
returns
result = true # or false
check if online notifcation should be shown for this user as already seen with current state
ticket = Ticket.find(1)
seen = ticket.online_notification_seen_state(check_user_id)
returns
result = true # or false
=end
def online_notification_seen_state(user_id_check = nil)
state = Ticket::State.lookup( id: state_id )
state_type = Ticket::StateType.lookup( id: state.state_type_id )
# set all to seen if pending action state is a closed or merged state
if state_type.name == 'pending action' && state.next_state_id
2015-07-26 21:56:50 +00:00
state = Ticket::State.lookup( id: state.next_state_id )
state_type = Ticket::StateType.lookup( id: state.state_type_id )
end
# set all to seen if new state is pending reminder state
if state_type.name == 'pending reminder'
if user_id_check
return false if owner_id == 1
return false if updated_by_id != owner_id && user_id_check == owner_id
return true
end
return true
end
# set all to seen if new state is a closed or merged state
return true if state_type.name == 'closed'
return true if state_type.name == 'merged'
false
2012-07-03 13:24:31 +00:00
end
2015-09-17 01:04:16 +00:00
def self.selectors(selectors, limit = 10)
return if !selectors
query, bind_params, tables = _selectors(selectors)
return [] if !query
ticket_count = Ticket.where(query, *bind_params).joins(tables).count
tickets = Ticket.where(query, *bind_params).joins(tables).limit(limit)
2015-09-17 01:04:16 +00:00
[ticket_count, tickets]
end
def self._selectors(selectors)
return if !selectors
query = ''
bind_params = []
tables = []
selectors.each {|attribute, selector|
selector = attribute.split(/\./)
next if !selector[1]
next if selector[0] == 'ticket'
next if tables.include?(selector[0])
tables.push selector[0].to_sym
}
2015-09-17 01:04:16 +00:00
selectors.each {|attribute, selector|
if query != ''
query += ' AND '
end
next if !selector
next if !selector.respond_to?(:key?)
next if !selector['operator']
return nil if !selector['value']
return nil if selector['value'].respond_to?(:empty?) && selector['value'].empty?
attributes = attribute.split(/\./)
attribute = "#{attributes[0]}s.#{attributes[1]}"
2015-09-17 01:04:16 +00:00
if selector['operator'] == 'is'
query += "#{attribute} IN (?)"
bind_params.push selector['value']
elsif selector['operator'] == 'is not'
query += "#{attribute} NOT IN (?)"
bind_params.push selector['value']
elsif selector['operator'] == 'contains'
query += "#{attribute} LIKE (?)"
value = "%#{selector['value']}%"
bind_params.push value
elsif selector['operator'] == 'contains not'
query += "#{attribute} NOT LIKE (?)"
value = "%#{selector['value']}%"
bind_params.push value
elsif selector['operator'] == 'before (absolute)'
query += "#{attribute} <= ?"
bind_params.push selector['value']
elsif selector['operator'] == 'after (absolute)'
query += "#{attribute} >= ?"
2015-09-17 01:04:16 +00:00
bind_params.push selector['value']
elsif selector['operator'] == 'before (relative)'
query += "#{attribute} <= ?"
bind_params.push Time.zone.now - selector['value'].to_i.minutes
elsif selector['operator'] == 'after (relative)'
query += "#{attribute} >= ?"
bind_params.push Time.zone.now + selector['value'].to_i.minutes
2015-09-17 01:04:16 +00:00
else
fail "Invalid operator '#{selector['operator']}' for '#{selector['value'].inspect}'"
end
}
[query, bind_params, tables]
2015-09-17 01:04:16 +00:00
end
2012-11-28 10:03:17 +00:00
private
def check_generate
return if number
self.number = Ticket::Number.generate
end
def check_title
return if !title
title.gsub!(/\s|\t|\r/, ' ')
end
def check_defaults
if !owner_id
self.owner_id = 1
end
return if !customer_id
customer = User.find( customer_id )
return if organization_id == customer.organization_id
self.organization_id = customer.organization_id
end
2013-06-12 14:57:29 +00:00
def reset_pending_time
# ignore if no state has changed
return if !changes['state_id']
# check if new state isn't pending*
current_state = Ticket::State.lookup( id: state_id )
current_state_type = Ticket::StateType.lookup( id: current_state.state_type_id )
# in case, set pending_time to nil
return if current_state_type.name =~ /^pending/i
self.pending_time = nil
end
def destroy_dependencies
# delete articles
articles.destroy_all
# destroy online notifications
OnlineNotification.remove( self.class.to_s, id )
end
2012-04-10 14:06:46 +00:00
end