diff --git a/app/assets/javascripts/app/controllers/_dashboard/stats.coffee b/app/assets/javascripts/app/controllers/_dashboard/stats.coffee
index 7fa9674ba..3a797a52b 100644
--- a/app/assets/javascripts/app/controllers/_dashboard/stats.coffee
+++ b/app/assets/javascripts/app/controllers/_dashboard/stats.coffee
@@ -12,8 +12,8 @@ class App.DashboardStats extends App.Controller
@render()
render: (data = {}) ->
- if !data.TicketResponseTime
- data.TicketResponseTime =
+ if !data.StatsTicketWaitingTime
+ data.StatsTicketWaitingTime =
handling_time: 0
average: 0
average_per_agent: 0
@@ -60,10 +60,10 @@ class App.DashboardStats extends App.Controller
@html App.view('dashboard/stats')(data)
- if data.TicketResponseTime
- @renderWidgetClockFace data.TicketResponseTime.handling_time
+ if data.StatsTicketWaitingTime
+ @renderWidgetClockFace data.StatsTicketWaitingTime.handling_time, data.StatsTicketWaitingTime.state, data.StatsTicketWaitingTime.percent
- renderWidgetClockFace: (time, max_time = 60) =>
+ renderWidgetClockFace: (time, state, percent) =>
canvas = @el.find 'canvas'
ctx = canvas.get(0).getContext '2d'
radius = 26
@@ -73,17 +73,15 @@ class App.DashboardStats extends App.Controller
canvas.attr 'width', 2 * radius
canvas.attr 'height', 2 * radius
- time = max_time if time > max_time
-
handlingTimeColors = {}
- handlingTimeColors[max_time/12] = '#38AE6A' # supergood
- handlingTimeColors[max_time/6] = '#A9AC41' # good
- handlingTimeColors[max_time/4] = '#FAAB00' # ok
- handlingTimeColors[max_time/3] = '#F6820B' # bad
- handlingTimeColors[max_time/2] = '#F35910' # superbad
+ handlingTimeColors['supergood'] = '#38AE6A' # supergood
+ handlingTimeColors['good'] = '#A9AC41' # good
+ handlingTimeColors['ok'] = '#FAAB00' # ok
+ handlingTimeColors['bad'] = '#F6820B' # bad
+ handlingTimeColors['superbad'] = '#F35910' # superbad
- for handlingTime, timeColor of handlingTimeColors
- if time <= handlingTime
+ for handlingState, timeColor of handlingTimeColors
+ if state == handlingState
backgroundColor = timeColor
break
@@ -101,7 +99,7 @@ class App.DashboardStats extends App.Controller
ctx.beginPath()
ctx.moveTo radius, radius
- arcsector = Math.PI * 2 * time/max_time
+ arcsector = Math.PI * 2 * percent
ctx.arc radius, radius, radius, -Math.PI/2, arcsector - Math.PI/2, false
ctx.lineTo radius, radius
ctx.closePath()
diff --git a/app/assets/javascripts/app/views/dashboard/stats.jst.eco b/app/assets/javascripts/app/views/dashboard/stats.jst.eco
index 5312d1477..940f38c1d 100644
--- a/app/assets/javascripts/app/views/dashboard/stats.jst.eco
+++ b/app/assets/javascripts/app/views/dashboard/stats.jst.eco
@@ -8,8 +8,8 @@
- <%- @T('My handling time: %s minutes', @TicketResponseTime.handling_time) %>
- <%- @T('Average: %s minutes', @TicketResponseTime.average_per_agent) %>
+ <%- @T('My handling time: %s minutes', @StatsTicketWaitingTime.handling_time) %>
+ <%- @T('Average: %s minutes', @StatsTicketWaitingTime.average_per_agent) %>
diff --git a/app/models/ticket.rb b/app/models/ticket.rb
index c8065361f..863338ca8 100644
--- a/app/models/ticket.rb
+++ b/app/models/ticket.rb
@@ -311,7 +311,7 @@ returns
self.state_id = Ticket::State.lookup(name: 'merged').id
# rest owner
- self.owner_id = User.find_by(login: '-').id
+ self.owner_id = 1
# save ticket
save!
diff --git a/lib/stats.rb b/lib/stats.rb
index 0b994953a..7d7eb7e0d 100644
--- a/lib/stats.rb
+++ b/lib/stats.rb
@@ -24,6 +24,7 @@ returns
Stats::TicketLoadMeasure,
Stats::TicketEscalation,
Stats::TicketReopen,
+ Stats::TicketWaitingTime,
]
# generate stats per agent
diff --git a/lib/stats/ticket_waiting_time.rb b/lib/stats/ticket_waiting_time.rb
new file mode 100644
index 000000000..7a7bda2a4
--- /dev/null
+++ b/lib/stats/ticket_waiting_time.rb
@@ -0,0 +1,73 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+
+class Stats::TicketWaitingTime
+
+ def self.generate(user)
+
+ open_state_ids = Ticket::State.by_category(:open).pluck(:id)
+
+ # get users groups
+ group_ids = user.groups.map(&:id)
+
+ own_waiting = Ticket.where(
+ 'owner_id = ? AND group_id IN (?) AND state_id IN (?) AND updated_at > ?', user.id, group_ids, open_state_ids, Time.zone.today
+ )
+ all_waiting = Ticket.where(
+ 'group_id IN (?) AND state_id IN (?) AND updated_at > ?', group_ids, open_state_ids, Time.zone.today
+ )
+
+ handling_time = calculate_average(own_waiting, Time.zone.today)
+ if handling_time.positive?
+ handling_time = (handling_time / 60).round
+ end
+ average_per_agent = calculate_average(all_waiting, Time.zone.today)
+ if average_per_agent.positive?
+ average_per_agent = (average_per_agent / 60).round
+ end
+
+ state = 'supergood'
+ percent = 0
+ state = if handling_time <= 60
+ percent = handling_time.to_f / 60
+ 'supergood'
+ elsif handling_time <= 60 * 4
+ percent = (handling_time.to_f - 60) / (60 * 3)
+ 'good'
+ elsif handling_time <= 60 * 8
+ percent = (handling_time.to_f - 60 * 4) / (60 * 4)
+ 'ok'
+ else
+ percent = 1.00
+ 'bad'
+ end
+
+ {
+ handling_time: handling_time,
+ average_per_agent: average_per_agent,
+ state: state,
+ percent: percent,
+ }
+ end
+
+ def self.average_state(result, _user_id)
+ result
+ end
+
+ def self.calculate_average(tickets, start_time)
+ average_time = 0
+ count_time = 0
+
+ tickets.each { |ticket|
+ ticket.articles.joins(:type).where('ticket_articles.created_at > ? AND ticket_articles.internal = ? AND ticket_article_types.communication = ?', start_time, false, true).each { |article|
+ if article.sender.name == 'Customer'
+ count_time = article.created_at.to_i
+ else
+ average_time += article.created_at.to_i - count_time
+ count_time = 0
+ end
+ }
+ }
+
+ average_time
+ end
+end
diff --git a/test/unit/stats_ticket_waiting_time_test.rb b/test/unit/stats_ticket_waiting_time_test.rb
new file mode 100644
index 000000000..d2d72d784
--- /dev/null
+++ b/test/unit/stats_ticket_waiting_time_test.rb
@@ -0,0 +1,150 @@
+# encoding: utf-8
+require 'test_helper'
+require 'stats/ticket_waiting_time'
+
+class StatsTicketWaitingTimeTest < ActiveSupport::TestCase
+
+ test 'single ticket' do
+ ticket1 = Ticket.create(
+ title: 'com test 1',
+ group: Group.lookup(name: 'Users'),
+ customer_id: 2,
+ state: Ticket::State.lookup(name: 'new'),
+ priority: Ticket::Priority.lookup(name: '2 normal'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ # communication 1: waiting time 2 hours (BUT too old yesterday)
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Customer'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-12 08:00',
+ updated_at: '2017-04-12 08:00',
+ )
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Agent'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-12 10:00',
+ updated_at: '2017-04-12 10:00',
+ )
+
+ # communication 2: waiting time 2 hours
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Customer'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-13 08:00',
+ updated_at: '2017-04-13 08:00',
+ )
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Agent'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-13 10:00',
+ updated_at: '2017-04-13 10:00',
+ )
+
+ # communication 3: waiting time 4 hours
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'Customer'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-13 11:00',
+ updated_at: '2017-04-13 11:00',
+ )
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: false,
+ sender: Ticket::Article::Sender.find_by(name: 'System'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-13 15:00',
+ updated_at: '2017-04-13 15:00',
+ )
+
+ # communication 4: INVALID waiting time 1 hour (because internal)
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: true,
+ sender: Ticket::Article::Sender.find_by(name: 'Customer'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-13 15:00',
+ updated_at: '2017-04-13 15:00',
+ )
+ Ticket::Article.create(
+ ticket_id: ticket1.id,
+ from: 'a@example.com',
+ to: 'a@example.com',
+ subject: 'com test 1',
+ message_id: 'some@id_com_1',
+ body: 'some message 123',
+ internal: true,
+ sender: Ticket::Article::Sender.find_by(name: 'System'),
+ type: Ticket::Article::Type.find_by(name: 'email'),
+ updated_by_id: 1,
+ created_by_id: 1,
+ created_at: '2017-04-13 15:10',
+ updated_at: '2017-04-13 15:10',
+ )
+
+ average_time = Stats::TicketWaitingTime.calculate_average([ticket1, ticket1], '2017-04-13 00:00:00')
+ assert_equal(60 * 60 * 6 * 2, average_time)
+ end
+
+end