Init version of SLA calculation.

This commit is contained in:
Martin Edenhofer 2013-03-05 13:31:23 +01:00
parent 77a4167b72
commit f7f55c52f0
10 changed files with 152 additions and 23 deletions

View file

@ -76,4 +76,5 @@ group :development, :test do
end
gem 'business_time'
gem 'thin'

View file

@ -421,6 +421,8 @@ class App.ControllerForm extends App.Controller
# radio
else if attribute.tag is 'working_hour'
if !attribute.value
attribute.value = {}
item = $( App.view('generic/working_hour')( attribute: attribute ) )
# ticket attribute selection

View file

@ -1,5 +1,3 @@
$ = jQuery.sub()
class Index extends App.Controller
constructor: ->
super

View file

@ -1,18 +1,26 @@
class App.Sla extends Spine.Model
@configure 'Sla', 'name', 'condition', 'data', 'active'
@configure 'Sla', 'name', 'first_response_time', 'update_time', 'close_time', 'condition', 'data', 'active'
@extend Spine.Model.Ajax
@url: 'api/slas'
@configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false, 'class': 'span4' },
{ name: 'first_response_time', display: 'First Resposne Time', tag: 'input', type: 'text', limit: 100, null: true, 'class': 'span4' },
{ name: 'update_time', display: 'Update Time', tag: 'input', type: 'text', limit: 100, null: true, 'class': 'span4' },
{ name: 'solution_time', display: 'Solution Time', tag: 'input', type: 'text', limit: 100, null: true, 'class': 'span4' },
{ name: 'condition', display: 'Conditions where SLA is used', tag: 'ticket_attribute_selection', null: true, class: 'span4' },
{ name: 'close_time', display: 'Solution Time', tag: 'input', type: 'text', limit: 100, null: true, 'class': 'span4' },
{ name: 'condition', display: 'Conditions where SLA is used', tag: 'ticket_attribute_selection', null: true, class: 'span4' },
{
name: 'working_hour'
name: 'data'
display: 'Working Hours'
tag: 'working_hour'
default: ''
default: {
Mon: true
Tue: true
Wed: true
Thu: true
Fri: true
beginning_of_workday: '8:00'
end_of_workday: '18:00'
}
null: true
nulloption: true
translate: true

View file

@ -1,19 +1,24 @@
<table>
<label><%- @T('Days') %></label>
<table style="width:70%">
<thead>
<tr>
<% for hour in [ 0 .. 23 ]: %>
<th><%- hour %></th>
<% for day in ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']: %>
<td><%- @T(day) %></td>
<% end %>
</tr>
</thead>
<tbody>
<% for day in ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']: %>
<tr>
<td><%- @T(day) %></td>
<% for hour in [ 0 .. 23 ]: %>
<td><input type="checkbox" value="1" name="<%- day %>-<%- hour %>"></td>
<% for day in ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']: %>
<td style="padding:2px"><input type="checkbox" name="<%= @attribute.name %>::<%- day %>" value="<%- day %>" <% if @attribute.value[day]: %>checked<% end %> /></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</table>
<div class="">
<label><%- @T('Hours') %></label>
<input type="text" class="span2" name="<%= @attribute.name %>::beginning_of_workday" value="<%= @attribute.value['beginning_of_workday'] %>"/>
-
<input type="text" class="span2" name="<%= @attribute.name %>::end_of_workday" value="<%= @attribute.value['end_of_workday'] %>"/>
</div>

View file

@ -0,0 +1,26 @@
class Observer::Ticket::EscalationCalculation < ActiveRecord::Observer
observe 'ticket', 'ticket::_article'
def after_create(record)
end
def after_update(record)
# return if we run import mode
return if Setting.get('import_mode')
# prevent loops
return if record[:escalation_calc]
record[:escalation_calc] = true
# do not recalculation if first respons is already out
if record.class.name == 'Ticket::Article'
return true if record.ticket.first_response
record.ticket.escalation_calculation
return true
end
# update escalation
record.escalation_calculation
end
end

View file

@ -403,6 +403,81 @@ class Ticket < ApplicationModel
return adapter
end
def escalation_calculation
# get sla
sla_selected = nil
Sla.where( :active => true ).each {|sla|
if sla.condition
puts sla.condition.inspect
hit = false
if sla.condition['tickets.ticket_priority_id']
if sla.condition['tickets.ticket_priority_id'].class == String
sla.condition['tickets.ticket_priority_id'] = [ sla.condition['tickets.ticket_priority_id'].to_i ]
end
if sla.condition['tickets.ticket_priority_id'].include?( self.ticket_priority_id )
hit = true
else
hit = false
end
end
if hit
sla_selected = sla
end
end
}
return if !sla_selected
# get calendar settings
BusinessTime::Config.beginning_of_workday = sla_selected.data['beginning_of_workday']
BusinessTime::Config.end_of_workday = sla_selected.data['end_of_workday']
days = []
['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].each {|day|
if sla_selected.data[day]
days.push day.downcase.to_sym
end
}
BusinessTime::Config.work_week = days
# puts sla_selected.inspect
# puts days.inspect
# first response
if sla_selected.first_response_time
created_at = Time.parse(self.created_at.to_s)
self.first_response_escal_date = (sla_selected.first_response_time / 60).round.business_hour.after( created_at )
# self.first_response_sla_time =
#!self.first_response &&
end
if self.first_response && !self.first_response_in_min
created_at = Time.parse(self.created_at.to_s)
first_response_at = Time.parse(self.first_response.to_s)
diff = created_at.business_time_until(first_response_at) / 60
self.first_response_in_min = diff.round
end
# # update time
# if sla_selected.close_time
# created_at = Time.parse(self.created_at.to_s)
# self.close_time_escal_date = (sla_selected.close_time / 60).round.business_hour.after( created_at )
# end
# close time
if sla_selected.close_time
created_at = Time.parse(self.created_at.to_s)
self.close_time_escal_date = (sla_selected.close_time / 60).round.business_hour.after( created_at )
end
if self.close_time && !self.close_time_in_min
created_at = Time.parse(self.created_at.to_s)
closed_at = Time.parse(self.close_time.to_s)
diff = created_at.business_time_until(closed_at) / 60
self.close_time_in_min = diff.round
end
self.save
end
private
def number_generate

View file

@ -40,7 +40,8 @@ module Zammad
'observer::_ticket::_article::_communicate_twitter',
'observer::_ticket::_notification',
'observer::_tag::_ticket_history',
'observer::_ticket::_reset_new_state'
'observer::_ticket::_reset_new_state',
'observer::_ticket::_escalation_calculation'
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.

View file

@ -1,12 +1,15 @@
class CreateSla < ActiveRecord::Migration
def up
create_table :slas do |t|
t.column :name, :string, :limit => 150, :null => true
t.column :condition, :string, :limit => 5000, :null => true
t.column :data, :string, :limit => 5000, :null => true
t.column :active, :boolean, :null => false, :default => true
t.column :updated_by_id, :integer, :null => false
t.column :created_by_id, :integer, :null => false
t.column :name, :string, :limit => 150, :null => true
# t.column :first_response_time, :integer, :null => true
# t.column :update_time, :integer, :null => true
# t.column :close_time, :integer, :null => true
t.column :condition, :string, :limit => 5000, :null => true
t.column :data, :string, :limit => 5000, :null => true
t.column :active, :boolean, :null => false, :default => true
t.column :updated_by_id, :integer, :null => false
t.column :created_by_id, :integer, :null => false
t.timestamps
end
add_index :slas, [:name], :unique => true

View file

@ -0,0 +1,10 @@
class UpdateSla < ActiveRecord::Migration
def up
add_column :slas, :first_response_time, :integer, :null => true
add_column :slas, :update_time, :integer, :null => true
add_column :slas, :close_time, :integer, :null => true
end
def down
end
end