Просмотр исходного кода

Init version of SLA calculation.

Martin Edenhofer 12 лет назад
Родитель
Сommit
f7f55c52f0

+ 1 - 0
Gemfile

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

+ 2 - 0
app/assets/javascripts/app/controllers/_application_controller_form.js.coffee

@@ -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

+ 0 - 2
app/assets/javascripts/app/controllers/sla.js.coffee

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

+ 13 - 5
app/assets/javascripts/app/models/sla.js.coffee

@@ -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

+ 14 - 9
app/assets/javascripts/app/views/generic/working_hour.jst.eco

@@ -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>

+ 26 - 0
app/models/observer/ticket/escalation_calculation.rb

@@ -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

+ 75 - 0
app/models/ticket.rb

@@ -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

+ 2 - 1
config/application.rb

@@ -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.

+ 9 - 6
db/migrate/20130201071513_create_sla.rb

@@ -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

+ 10 - 0
db/migrate/20130305111945_update_sla.rb

@@ -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