From 7b15323315e0b7cf9a99473b451fb03895b8c8e0 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 6 Jun 2013 09:34:09 +0200 Subject: [PATCH 1/7] Added time zone support for slas. --- .../_application_controller_form.js.coffee | 35 +++++++++++++++---- .../javascripts/app/models/sla.js.coffee | 5 +-- app/controllers/application_controller.rb | 18 +++++++++- db/migrate/20130606070432_sla_timezone.rb | 9 +++++ 4 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20130606070432_sla_timezone.rb diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index 0ea55400f..8e1042fdf 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -157,7 +157,7 @@ class App.ControllerForm extends App.Controller # set value if @params - + # check if we have a references parts = attribute.name.split '::' if parts[0] && parts[1] @@ -201,8 +201,8 @@ class App.ControllerForm extends App.Controller # build options list if _.isEmpty(attribute.options) attribute.options = [ - { name: 'active', value: true } - { name: 'inactive', value: false } + { name: 'active', value: true } + { name: 'inactive', value: false } ] # update boolean types @@ -221,6 +221,27 @@ class App.ControllerForm extends App.Controller else if attribute.tag is 'select' item = $( App.view('generic/select')( attribute: attribute ) ) + # timezone + else if attribute.tag is 'timezone' + attribute.options = [] + timezones = App.Config.get('timezones') + + # build list based on config + for timezone_value, timezone_diff of timezones + if timezone_diff > 0 + timezone_diff = '+' + timezone_diff + item = + name: "#{timezone_value} (GMT#{timezone_diff})" + value: timezone_value + attribute.options.push item + + # finde selected item of list + for record in attribute.options + if record.value is attribute.value + record.selected = 'selected' + + item = $( App.view('generic/select')( attribute: attribute ) ) + # select else if attribute.tag is 'input_select' item = $('
') @@ -374,7 +395,7 @@ class App.ControllerForm extends App.Controller onRemoveTag: onRemoveTag ) siteUpdate(true) - + # update box size App.Event.bind 'ui:rerender:content', => siteUpdate(true) @@ -493,7 +514,7 @@ class App.ControllerForm extends App.Controller name = 'owner_id' if key is 'customer_id' display = 'Customer' - name = 'customer_id' + name = 'customer_id' attribute_config = { name: attribute.name + '::tickets.' + name display: display @@ -674,7 +695,7 @@ class App.ControllerForm extends App.Controller ) # itemSub.append('') item.find('.ticket_attribute_item').append( itemSub ) - + # list of shown attributes show = [] @@ -793,7 +814,7 @@ class App.ControllerForm extends App.Controller selected: true disable: false }, - + # { # value: 'tag' # name: 'Tag' diff --git a/app/assets/javascripts/app/models/sla.js.coffee b/app/assets/javascripts/app/models/sla.js.coffee index 7f50cf6fb..e89e0b9cf 100644 --- a/app/assets/javascripts/app/models/sla.js.coffee +++ b/app/assets/javascripts/app/models/sla.js.coffee @@ -1,5 +1,5 @@ class App.Sla extends App.Model - @configure 'Sla', 'name', 'first_response_time', 'update_time', 'close_time', 'condition', 'data', 'active' + @configure 'Sla', 'name', 'first_response_time', 'update_time', 'close_time', 'condition', 'timezone', 'data', 'active' @extend Spine.Model.Ajax @url: 'api/slas' @configure_attributes = [ @@ -8,7 +8,8 @@ class App.Sla extends App.Model { name: 'update_time', display: 'Update Time', tag: 'input', type: 'text', limit: 100, null: true, 'class': 'span4', note: 'In minutes, only business times are counted.' }, { name: 'close_time', display: 'Solution Time', tag: 'input', type: 'text', limit: 100, null: true, 'class': 'span4', note: 'In minutes, only business times are counted.' }, { name: 'condition', display: 'Conditions where SLA is used', tag: 'ticket_attribute_selection', null: true, class: 'span4' }, - { + { name: 'timezone', display: 'Timezone', tag: 'timezone', null: true, class: 'span4' }, + { name: 'data' display: 'Business Times' tag: 'working_hour' diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b4d5fe246..7ba669f47 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -196,12 +196,28 @@ class ApplicationController < ActionController::Base end def config_frontend - + # config config = {} Setting.select('name').where( :frontend => true ).each { |setting| config[setting.name] = Setting.get(setting.name) } + + # get all time zones + config['timezones'] = {} + TZInfo::Timezone.all.each { |t| + + # ignore the following time zones + next if t.name =~ /^GMT/ + next if t.name =~ /^Etc/ + next if t.name =~ /^MET/ + next if t.name =~ /^MST/ + next if t.name =~ /^ROC/ + next if t.name =~ /^ROK/ + diff = t.current_period.utc_total_offset / 60 /60 + config['timezones'][ t.name ] = diff + } + return config end diff --git a/db/migrate/20130606070432_sla_timezone.rb b/db/migrate/20130606070432_sla_timezone.rb new file mode 100644 index 000000000..495e63175 --- /dev/null +++ b/db/migrate/20130606070432_sla_timezone.rb @@ -0,0 +1,9 @@ +class SlaTimezone < ActiveRecord::Migration + def up + add_column :slas, :timezone, :string, :limit => 50, :null => true + end + + def down + remove_column :slas, :timezone + end +end From b75f900bcd83f6751b53ed8ee8f19a5c0c65238e Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 6 Jun 2013 11:54:21 +0200 Subject: [PATCH 2/7] Added pids directory. --- tmp/pids/README | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tmp/pids/README diff --git a/tmp/pids/README b/tmp/pids/README new file mode 100644 index 000000000..e69de29bb From c06a768a49b69351b39ff6b50ab537a31e73c8b5 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 6 Jun 2013 16:23:20 +0200 Subject: [PATCH 3/7] Added pids directory. --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index afc30d9cf..4177061f1 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ # Ignore all logfiles and tempfiles. /log/*.log -/tmp/* +/tmp/websocket/* +/tmp/cache/* +/tmp/pids/* # Ignore .project files /.project From 7dd0208618fe5af3c4197306eae56645e0e9ab65 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 6 Jun 2013 16:24:10 +0200 Subject: [PATCH 4/7] Added missing translations. --- db/seeds.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/db/seeds.rb b/db/seeds.rb index a006227e3..379a8aa5a 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1794,6 +1794,20 @@ Translation.create_if_not_exists( :locale => 'de', :source => "Add", :target => Translation.create_if_not_exists( :locale => 'de', :source => "Call Outbound", :target => "Anruf ausgehend" ) Translation.create_if_not_exists( :locale => 'de', :source => "Call Inbound", :target => "Anruf eingehend" ) Translation.create_if_not_exists( :locale => 'de', :source => "Loading...", :target => "Laden..." ) +Translation.create_if_not_exists( :locale => 'de', :source => "Work Disposition", :target => "Arbeitsverteilung" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Timezone", :target => "Zeitzone" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Business Times", :target => "Arbeitszeiten" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Day", :target => "Day" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Days", :target => "Days" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Hour", :target => "Stunde" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Hours", :target => "Stunden" ) +Translation.create_if_not_exists( :locale => 'de', :source => "New SLA", :target => "Neuer SLA" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Conditions where SLA is used", :target => "Bedingungen bei denen der SLA verwendet wird" ) +Translation.create_if_not_exists( :locale => 'de', :source => "First Response Time", :target => "Reaktionszeit" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Update Time", :target => "Aktuallisierungszeit" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Solution Time", :target => "Lösungszeit" ) +Translation.create_if_not_exists( :locale => 'de', :source => "Add Attribute", :target => "Attribut hinzufügen" ) +Translation.create_if_not_exists( :locale => 'de', :source => "", :target => "" ) #Translation.create_if_not_exists( :locale => 'de', :source => "", :target => "" ) From 3e3f268566c1a4173b43fbd0e5bf5cb759926be6 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 7 Jun 2013 07:57:52 +0200 Subject: [PATCH 5/7] Added support of timezones in escalation calculation. --- app/models/ticket.rb | 10 ++-- lib/time_calculation.rb | 20 ++++++- test/unit/ticket_test.rb | 104 +++++++++++++++++++++++++++++++-- test/unit/working_time_test.rb | 4 +- 4 files changed, 126 insertions(+), 12 deletions(-) diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 613f4265a..0e3e2e6b7 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -504,7 +504,7 @@ class Ticket < ApplicationModel when Symbol, String require "ticket/number/#{adapter_name.to_s.downcase}" adapter = Ticket::Number.const_get("#{adapter_name.to_s.capitalize}") - else + else raise "Missing number_adapter '#{adapter_name}'" end return adapter @@ -522,7 +522,7 @@ class Ticket < ApplicationModel } end - def _escalation_calculation_get_sla + def _escalation_calculation_get_sla(time) sla_selected = nil sla_list = Cache.get( 'SLA::List::Active' ) @@ -559,7 +559,7 @@ class Ticket < ApplicationModel # get and set calendar settings if sla_selected - TimeCalculation.config( sla_selected.data ) + TimeCalculation.config( sla_selected.data, sla_selected.timezone, time ) end return sla_selected end @@ -588,7 +588,7 @@ class Ticket < ApplicationModel end # get sla for ticket - sla_selected = self._escalation_calculation_get_sla + sla_selected = self._escalation_calculation_get_sla(self.created_at) # reset escalation if no sla is set if !sla_selected @@ -704,4 +704,4 @@ class Ticket < ApplicationModel class Number end -end \ No newline at end of file +end diff --git a/lib/time_calculation.rb b/lib/time_calculation.rb index 9d5bb59ef..04daa2060 100644 --- a/lib/time_calculation.rb +++ b/lib/time_calculation.rb @@ -4,7 +4,25 @@ require 'business_time/core_ext/fixnum_minute' require 'business_time/core_ext/time_fix' module TimeCalculation - def self.config(config) + def self.config(config, timezone, start_time) + time_diff = 0 + if timezone + begin + time_diff = Time.parse(start_time.to_s).in_time_zone(timezone).utc_offset + rescue Exception => e + puts "ERROR: Can't fine tomezone #{timezone}" + puts e.inspect + puts e.backtrace + end + end + beginning_of_workday = Time.parse("1977-10-27 #{config['beginning_of_workday']}") + time_diff + if beginning_of_workday + config['beginning_of_workday'] = "#{beginning_of_workday.hour}:#{beginning_of_workday.min}" + end + end_of_workday = Time.parse("1977-10-27 #{config['end_of_workday']}") + time_diff + if end_of_workday + config['end_of_workday'] = "#{end_of_workday.hour}:#{end_of_workday.min}" + end BusinessTime::Config.beginning_of_workday = config['beginning_of_workday'] BusinessTime::Config.end_of_workday = config['end_of_workday'] days = [] diff --git a/test/unit/ticket_test.rb b/test/unit/ticket_test.rb index 28c183704..96672efb8 100644 --- a/test/unit/ticket_test.rb +++ b/test/unit/ticket_test.rb @@ -1,6 +1,6 @@ # encoding: utf-8 require 'test_helper' - + class TicketTest < ActiveSupport::TestCase test 'ticket create' do ticket = Ticket.create( @@ -195,7 +195,7 @@ class TicketTest < ActiveSupport::TestCase assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.close_time_escal_date verify 3' ) assert_equal( ticket.close_time_in_min, nil, 'ticket.close_time_in_min verify 3' ) assert_equal( ticket.close_time_diff_in_min, nil, 'ticket.close_time_diff_in_min verify 3' ) - + # set first reponse over time ticket.update_attributes( :first_response => '2013-03-21 14:00:00 UTC', @@ -214,7 +214,7 @@ class TicketTest < ActiveSupport::TestCase assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.close_time_escal_date verify 4' ) assert_equal( ticket.close_time_in_min, nil, 'ticket.close_time_in_min verify 4' ) - assert_equal( ticket.close_time_diff_in_min, nil, 'ticket.close_time_diff_in_min verify 4' ) + assert_equal( ticket.close_time_diff_in_min, nil, 'ticket.close_time_diff_in_min verify 4' ) # set update time in time ticket.update_attributes( @@ -432,4 +432,100 @@ class TicketTest < ActiveSupport::TestCase delete = sla.destroy assert( delete, "sla destroy" ) end -end \ No newline at end of file + + test 'ticket sla + timezone' do + + # cleanup + delete = Sla.destroy_all + assert( delete, "sla destroy_all" ) + delete = Ticket.destroy_all + assert( delete, "ticket destroy_all" ) + + ticket = Ticket.create( + :title => 'some title äöüß', + :group => Group.lookup( :name => 'Users'), + :customer_id => 2, + :ticket_state => Ticket::State.lookup( :name => 'new' ), + :ticket_priority => Ticket::Priority.lookup( :name => '2 normal' ), + :created_at => '2013-03-21 09:30:00 UTC', + :updated_at => '2013-03-21 09:30:00 UTC', + :updated_by_id => 1, + :created_by_id => 1, + ) + assert( ticket, "ticket created" ) + assert_equal( ticket.escalation_time, nil, 'ticket.escalation_time verify' ) + + # set sla's for timezone "Europe/Berlin" (+1), so UTC times are 8:00-17:00 + sla = Sla.create( + :name => 'test sla 1', + :condition => {}, + :data => { + "Mon"=>"Mon", "Tue"=>"Tue", "Wed"=>"Wed", "Thu"=>"Thu", "Fri"=>"Fri", "Sat"=>"Sat", "Sun"=>"Sun", + "beginning_of_workday" => "9:00", + "end_of_workday" => "18:00", + }, + :timezone => 'Europe/Berlin', + :first_response_time => 120, + :update_time => 180, + :close_time => 240, + :active => true, + :updated_by_id => 1, + :created_by_id => 1, + ) + ticket = Ticket.find(ticket.id) + assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 12:00:00 UTC', 'ticket.escalation_time verify 1' ) + assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 12:00:00 UTC', 'ticket.first_response_escal_date verify 1' ) + assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 13:00:00 UTC', 'ticket.update_time_escal_date verify 1' ) + assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 14:00:00 UTC', 'ticket.close_time_escal_date verify 1' ) + + delete = sla.destroy + assert( delete, "sla destroy" ) + + delete = ticket.destroy + assert( delete, "ticket destroy" ) + + ticket = Ticket.create( + :title => 'some title äöüß', + :group => Group.lookup( :name => 'Users'), + :customer_id => 2, + :ticket_state => Ticket::State.lookup( :name => 'new' ), + :ticket_priority => Ticket::Priority.lookup( :name => '2 normal' ), + :created_at => '2013-10-21 09:30:00 UTC', + :updated_at => '2013-10-21 09:30:00 UTC', + :updated_by_id => 1, + :created_by_id => 1, + ) + assert( ticket, "ticket created" ) + assert_equal( ticket.escalation_time, nil, 'ticket.escalation_time verify' ) + + # set sla's for timezone "Europe/Berlin" (+1), so UTC times are 8:00-17:00 + sla = Sla.create( + :name => 'test sla 1', + :condition => {}, + :data => { + "Mon"=>"Mon", "Tue"=>"Tue", "Wed"=>"Wed", "Thu"=>"Thu", "Fri"=>"Fri", "Sat"=>"Sat", "Sun"=>"Sun", + "beginning_of_workday" => "9:00", + "end_of_workday" => "18:00", + }, + :timezone => 'Europe/Berlin', + :first_response_time => 120, + :update_time => 180, + :close_time => 240, + :active => true, + :updated_by_id => 1, + :created_by_id => 1, + ) + ticket = Ticket.find(ticket.id) + assert_equal( ticket.escalation_time.gmtime.to_s, '2013-10-21 13:00:00 UTC', 'ticket.escalation_time verify 1' ) + assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-10-21 13:00:00 UTC', 'ticket.first_response_escal_date verify 1' ) + assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-10-21 14:00:00 UTC', 'ticket.update_time_escal_date verify 1' ) + assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-10-21 15:00:00 UTC', 'ticket.close_time_escal_date verify 1' ) + + delete = ticket.destroy + assert( delete, "ticket destroy" ) + + delete = sla.destroy + assert( delete, "sla destroy" ) + end + +end diff --git a/test/unit/working_time_test.rb b/test/unit/working_time_test.rb index 2ffa06941..c03abc95e 100644 --- a/test/unit/working_time_test.rb +++ b/test/unit/working_time_test.rb @@ -89,7 +89,7 @@ class WorkingTimeTest < ActiveSupport::TestCase }, ] tests.each { |test| - TimeCalculation.config( test[:config] ) + TimeCalculation.config( test[:config], nil, test[:start] ) diff = TimeCalculation.business_time_diff( test[:start], test[:end] ) assert_equal( diff, test[:diff], 'diff' ) } @@ -243,7 +243,7 @@ class WorkingTimeTest < ActiveSupport::TestCase }, ] tests.each { |test| - TimeCalculation.config( test[:config] ) + TimeCalculation.config( test[:config], nil, test[:start] ) dest_time = TimeCalculation.dest_time( test[:start] + ' UTC', test[:diff] ) assert_equal( dest_time.gmtime, Time.parse( test[:dest_time] + ' UTC' ), "dest time - #{test[:dest_time].to_s}" ) } From 9df719b8bf5b5fd07cf8dc88368d662d610f7884 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 7 Jun 2013 15:51:56 +0200 Subject: [PATCH 6/7] Rewrite of business time calculation. Is now working with timezones. --- app/models/ticket.rb | 16 +- lib/business_time/business_minutes.rb | 99 ------- lib/business_time/core_ext/fixnum_minute.rb | 11 - lib/business_time/core_ext/time_fix.rb | 130 --------- lib/time_calculation.rb | 295 +++++++++++++++++--- test/unit/ticket_test.rb | 65 ++++- test/unit/working_time_test.rb | 261 ++++++++++++++++- 7 files changed, 580 insertions(+), 297 deletions(-) delete mode 100644 lib/business_time/business_minutes.rb delete mode 100644 lib/business_time/core_ext/fixnum_minute.rb delete mode 100644 lib/business_time/core_ext/time_fix.rb diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 0e3e2e6b7..3b2ef0182 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -557,10 +557,6 @@ class Ticket < ApplicationModel end } - # get and set calendar settings - if sla_selected - TimeCalculation.config( sla_selected.data, sla_selected.timezone, time ) - end return sla_selected end @@ -609,13 +605,13 @@ class Ticket < ApplicationModel # first response if sla_selected.first_response_time - self.first_response_escal_date = TimeCalculation.dest_time( created_at, sla_selected.first_response_time ) + self.first_response_escal_date = TimeCalculation.dest_time( created_at, sla_selected.first_response_time, sla_selected.data, sla_selected.timezone ) # set ticket escalation self.escalation_time = self._escalation_calculation_higher_time( self.escalation_time, self.first_response_escal_date, self.first_response ) end if self.first_response# && !self.first_response_in_min - self.first_response_in_min = TimeCalculation.business_time_diff( self.created_at, self.first_response ) + self.first_response_in_min = TimeCalculation.business_time_diff( self.created_at, self.first_response, sla_selected.data, sla_selected.timezone ) end # set sla time if sla_selected.first_response_time && self.first_response_in_min @@ -629,13 +625,13 @@ class Ticket < ApplicationModel 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 ) + self.update_time_escal_date = TimeCalculation.dest_time( last_update, sla_selected.update_time, sla_selected.data, sla_selected.timezone ) # set ticket escalation self.escalation_time = self._escalation_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 ) + 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 @@ -646,13 +642,13 @@ class Ticket < ApplicationModel # close time if sla_selected.close_time - self.close_time_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.close_time ) + self.close_time_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.close_time, sla_selected.data, sla_selected.timezone ) # set ticket escalation self.escalation_time = self._escalation_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 = TimeCalculation.business_time_diff( self.created_at, self.close_time ) + self.close_time_in_min = TimeCalculation.business_time_diff( self.created_at, self.close_time, sla_selected.data, sla_selected.timezone ) end # set sla time if sla_selected.close_time && self.close_time_in_min diff --git a/lib/business_time/business_minutes.rb b/lib/business_time/business_minutes.rb deleted file mode 100644 index b37527d3f..000000000 --- a/lib/business_time/business_minutes.rb +++ /dev/null @@ -1,99 +0,0 @@ -module BusinessTime - - class BusinessMinutes - def initialize(minutes) - @minutes = minutes - end - - def ago - Time.zone ? before(Time.zone.now) : before(Time.now) - end - - def from_now - Time.zone ? after(Time.zone.now) : after(Time.now) - end - - def after(time) - after_time = Time.roll_forward(time) - # Step through the minutes, skipping over non-business minutes - days = @minutes / 60 / 24 - hours = ( @minutes - ( days * 60 * 24 ) ) / 60 - minutes = @minutes - ( (days * 60 * 24 ) + (hours * 60) ) - if @minutes > 60 * 12 - - end - - local_sec = @minutes * 60 - loop = true - while (loop == true) do - a = after_time - if local_sec >= 60 * 60 - after_time = after_time + 1.hour - else - after_time = after_time + 1.minute - end - - # Ignore minutes before opening and after closing - if (after_time > Time.end_of_workday(after_time)) - after_time = after_time + off_minutes - if local_sec < 60 * 60 - after_time = after_time - 60 - else - after_time = after_time - 60 * 60 - end - next - end - - # Ignore weekends and holidays - while !Time.workday?(after_time) - after_time = Time.beginning_of_workday(after_time + 1.day) - a = after_time - end - diff = after_time - a - local_sec = local_sec - diff - - if local_sec <= 0 - loop = false - next - end - - end - after_time - end - alias_method :since, :after - - def before(time) - before_time = Time.roll_forward(time) - # Step through the hours, skipping over non-business hours - @minutes.times do - before_time = before_time - 1.minute - - # Ignore hours before opening and after closing - if (before_time < Time.beginning_of_workday(before_time)) - before_time = before_time - off_minutes - end - - # Ignore weekends and holidays - while !Time.workday?(before_time) - before_time = before_time - 1.day - end - end - before_time - end - - private - - def off_minutes - return @gap if @gap - if Time.zone - gap_end = Time.zone.parse(BusinessTime::Config.beginning_of_workday) - gap_begin = (Time.zone.parse(BusinessTime::Config.end_of_workday)-1.day) - else - gap_end = Time.parse(BusinessTime::Config.beginning_of_workday) - gap_begin = (Time.parse(BusinessTime::Config.end_of_workday) - 1.day) - end - @gap = gap_end - gap_begin - end - end - -end diff --git a/lib/business_time/core_ext/fixnum_minute.rb b/lib/business_time/core_ext/fixnum_minute.rb deleted file mode 100644 index af6a894de..000000000 --- a/lib/business_time/core_ext/fixnum_minute.rb +++ /dev/null @@ -1,11 +0,0 @@ -# hook into fixnum so we can say things like: -# 5.business_minutes.from_now -# 4.business_minutes.before(some_date_time) -class Fixnum - include BusinessTime - - def business_minutes - BusinessMinutes.new(self) - end - alias_method :business_minute, :business_minutes -end \ No newline at end of file diff --git a/lib/business_time/core_ext/time_fix.rb b/lib/business_time/core_ext/time_fix.rb deleted file mode 100644 index ce000b22b..000000000 --- a/lib/business_time/core_ext/time_fix.rb +++ /dev/null @@ -1,130 +0,0 @@ -# Add workday and weekday concepts to the Time class -class Time - class << self - - # Gives the time at the end of the workday, assuming that this time falls on a - # workday. - # Note: It pretends that this day is a workday whether or not it really is a - # workday. - def end_of_workday(day) - format = "%B %d %Y #{BusinessTime::Config.end_of_workday}" - Time.zone ? Time.zone.parse(day.strftime(format)) : - Time.parse(day.strftime(format)) - end - - # Gives the time at the beginning of the workday, assuming that this time - # falls on a workday. - # Note: It pretends that this day is a workday whether or not it really is a - # workday. - def beginning_of_workday(day) - format = "%B %d %Y #{BusinessTime::Config.beginning_of_workday}" - Time.zone ? Time.zone.parse(day.strftime(format)) : - Time.parse(day.strftime(format)) - end - - # True if this time is on a workday (between 00:00:00 and 23:59:59), even if - # this time falls outside of normal business hours. - def workday?(day) - Time.weekday?(day) && - !BusinessTime::Config.holidays.include?(day.to_date) - end - - # True if this time falls on a weekday. - def weekday?(day) - BusinessTime::Config.weekdays.include? day.wday - end - - def before_business_hours?(time) - time < beginning_of_workday(time) - end - - def after_business_hours?(time) - time > end_of_workday(time) - end - - # Rolls forward to the next beginning_of_workday - # when the time is outside of business hours - def roll_forward(time) - if (Time.before_business_hours?(time) || !Time.workday?(time)) - next_business_time = Time.beginning_of_workday(time) - elsif Time.after_business_hours?(time + 1) - next_business_time = Time.beginning_of_workday(time) + 1.day - else - next_business_time = time.clone - end - - while !Time.workday?(next_business_time) - next_business_time += 1.day - end - - next_business_time - end - - end -end - -class Time - - def business_time_until(to_time) - - # Make sure that we will calculate time from A to B "clockwise" - direction = 1 - if self < to_time - time_a = self - time_b = to_time - else - time_a = to_time - time_b = self - direction = -1 - end - - # Align both times to the closest business hours - time_a = Time::roll_forward(time_a) - time_b = Time::roll_forward(time_b) - - # If same date, then calculate difference straight forward -# if time_a.to_date == time_b.to_date -# result = time_b - time_a -# return result *= direction -# end - - # Both times are in different dates - result = Time.parse(time_a.strftime('%Y-%m-%d ') + BusinessTime::Config.end_of_workday) - time_a # First day - result += time_b - Time.parse(time_b.strftime('%Y-%m-%d ') + BusinessTime::Config.beginning_of_workday) # Last day - - # All days in between -#puts "--- #{time_a}-#{time_b} - #{direction}" - -# duration_of_working_day = Time.parse(BusinessTime::Config.end_of_workday) - Time.parse(BusinessTime::Config.beginning_of_workday) -# result += (time_a.to_date.business_days_until(time_b.to_date) - 1) * duration_of_working_day - - result = 0 - - # All days in between - time_c = time_a - while time_c.to_i < time_b.to_i do - end_of_workday = Time.end_of_workday(time_c) - if !Time.workday?(time_c) - time_c = Time.beginning_of_workday(time_c) + 1.day -# puts 'VACATIONS! ' + time_c.to_s - end - if time_c.to_date == time_b.to_date - if end_of_workday < time_b - result += end_of_workday - time_c - break - else - result += time_b - time_c - break - end - else - result += end_of_workday - time_c - time_c = Time::roll_forward(end_of_workday) - end - result += 1 if end_of_workday.to_s =~ /23:59:59/ - end - - # Make sure that sign is correct - result *= direction - end - -end \ No newline at end of file diff --git a/lib/time_calculation.rb b/lib/time_calculation.rb index 04daa2060..f3e4608fc 100644 --- a/lib/time_calculation.rb +++ b/lib/time_calculation.rb @@ -1,10 +1,5 @@ -require 'business_time' -require 'business_time/business_minutes' -require 'business_time/core_ext/fixnum_minute' -require 'business_time/core_ext/time_fix' - module TimeCalculation - def self.config(config, timezone, start_time) + def self.working_hours(start_time, config, timezone) time_diff = 0 if timezone begin @@ -15,50 +10,286 @@ module TimeCalculation puts e.backtrace end end - beginning_of_workday = Time.parse("1977-10-27 #{config['beginning_of_workday']}") + time_diff - if beginning_of_workday - config['beginning_of_workday'] = "#{beginning_of_workday.hour}:#{beginning_of_workday.min}" - end - end_of_workday = Time.parse("1977-10-27 #{config['end_of_workday']}") + time_diff - if end_of_workday - config['end_of_workday'] = "#{end_of_workday.hour}:#{end_of_workday.min}" - end - BusinessTime::Config.beginning_of_workday = config['beginning_of_workday'] - BusinessTime::Config.end_of_workday = config['end_of_workday'] - days = [] - ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].each {|day| - if config[day] - days.push day.downcase.to_sym + beginning_of_workday = Time.parse("1977-10-27 #{config['beginning_of_workday']}") + end_of_workday = Time.parse("1977-10-27 #{config['end_of_workday']}") - 3600 + config_ok = false + working_hours = {} + [:Mon, :Tue, :Wed, :Thu, :Fri, :Sat, :Sun].each {|day| + working_hours[day] = [] + if config[day.to_s] == true || config[day.to_s] == day.to_s + config_ok = true + (0..23).each {|hour| + time = Time.parse("1977-10-27 #{hour}:00:00") + if time >= beginning_of_workday && time <= end_of_workday + working_hours[day].push true + else + working_hours[day].push nil + end + } end } - BusinessTime::Config.work_week = days - holidays = [] - if config['holidays'] - config['holidays'].each {|holiday| - date = Date.parse( holiday ) - holidays.push date.to_date + + if !config_ok + raise "sla config is invalid! " + config.inspect + end + + # shift working hours / if needed + if time_diff && time_diff != 0 + + hours_to_shift = (time_diff / 3600 ).round + move_items = { + :Mon => [], + :Tue => [], + :Wed => [], + :Thu => [], + :Fri => [], + :Sat => [], + :Sun => [], + } + (1..hours_to_shift).each {|count| + working_hours.each {|day, value| + if working_hours[day] + to_move = working_hours[day].shift + if day == :Mon + move_items[:Tue].push to_move + elsif day == :Tue + move_items[:Wed].push to_move + elsif day == :Wed + move_items[:Thu].push to_move + elsif day == :Thu + move_items[:Fri].push to_move + elsif day == :Fri + move_items[:Sat].push to_move + elsif day == :Sat + move_items[:Sun].push to_move + elsif day == :Sun + move_items[:Mon].push to_move + end + end + } + } + move_items.each {|day, value| + value.each {|item| + working_hours[day].push item + } } end - BusinessTime::Config.holidays = holidays + return working_hours end - def self.business_time_diff(start_time, end_time) + def self.business_time_diff(start_time, end_time, config, timezone = '') if start_time.class == String start_time = Time.parse( start_time.to_s + 'UTC' ) end if end_time.class == String end_time = Time.parse( end_time.to_s + 'UTC' ) end - diff = start_time.business_time_until( end_time ) / 60 + + working_hours = self.working_hours(start_time, config, timezone) + + week_day_map = { + 1 => :Mon, + 2 => :Tue, + 3 => :Wed, + 4 => :Thu, + 5 => :Fri, + 6 => :Sat, + 0 => :Sun, + } + + count = 0 + calculation = true + first_loop = true + while calculation do + week_day = start_time.wday + day = start_time.day + month = start_time.month + year = start_time.year + hour = start_time.hour + + + # check if it's vacation day + if config + if config['holidays'] + if config['holidays'].include?("#{year}-#{month}-#{day}") + + # jump to next day + start_time = start_time.beginning_of_day + 86400 + next + end + end + end + + # check if it's countable day + if working_hours[ week_day_map[week_day] ].empty? + + # jump to next day + start_time = start_time.beginning_of_day + 86400 + next + end + + # fillup to first full hour + if first_loop + diff = end_time - start_time + + if diff > 59 * 60 + diff = start_time - start_time.beginning_of_hour + end + start_time += diff + + # check if it's countable hour + if working_hours[ week_day_map[week_day] ][ hour ] + count += diff + end + end + first_loop = false + + # loop to next hour + (hour..23).each { |next_hour| + + # check if end time is lower + if start_time >= end_time + calculation = false + break + end + + # check if end_time is within this hour + diff = end_time - start_time + if diff > 59 * 60 + diff = 3600 + end + + # keep it in current day + if next_hour == 23 + start_time += diff-1 + else + start_time += diff + end + + # check if it's business hour and count + if working_hours[ week_day_map[week_day] ][ next_hour ] + count += diff + end + } + + # loop to next day + start_time = start_time.beginning_of_day + 86400 + end + + diff = count / 60 diff.round end - def self.dest_time(start_time, diff_in_min) + def self.dest_time(start_time, diff_in_min, config, timezone = '') if start_time.class == String start_time = Time.parse( start_time.to_s + ' UTC' ) end - dest_time = diff_in_min.round.business_minute.after( start_time ) - return dest_time + + # loop + working_hours = self.working_hours(start_time, config, timezone) + + week_day_map = { + 1 => :Mon, + 2 => :Tue, + 3 => :Wed, + 4 => :Thu, + 5 => :Fri, + 6 => :Sat, + 0 => :Sun, + } + + count = diff_in_min * 60 + calculation = true + first_loop = true + while calculation do + week_day = start_time.wday + day = start_time.day + month = start_time.month + year = start_time.year + hour = start_time.hour +#puts "start outer loop #{start_time}-#{week_day}-#{year}-#{month}-#{day}-#{hour}|c#{count}" + + # check if it's vacation day + if config + if config['holidays'] + if config['holidays'].include?("#{year}-#{month}-#{day}") + + # jump to next day + start_time = start_time.beginning_of_day + 86400 + next + end + end + end + + # check if it's countable day + if working_hours[ week_day_map[week_day] ].empty? + + # jump to next day + start_time = start_time.beginning_of_day + 86400 + next + end + + # fillup to first full hour + if first_loop + + # get rest of this hour + diff = 3600 - (start_time - start_time.beginning_of_hour) + start_time += diff + + # check if it's countable hour + if working_hours[ week_day_map[week_day] ][ hour ] + count -= diff + end + + # start on next hour of we moved to next + if diff != 0 + hour += 1 + end + end + + first_loop = false + + # loop to next hour + (hour..23).each { |next_hour| + + diff = 3600 + + # check if count positiv + if count <= 0 + calculation = false + break + end + + # check if it's business hour and count + if working_hours[ week_day_map[week_day] ][ next_hour ] + # check if count is within this hour + if count > 59 * 60 + diff = 3600 + else + diff = count + end + count -= diff + end + + # keep it in current day + if next_hour == 23 + start_time += diff-1 + else + start_time += diff + end + } + + # check if count positiv + if count <= 0 + calculation = false + break + end + + # loop to next day + start_time = start_time.beginning_of_day + 86400 + end + + return start_time end end diff --git a/test/unit/ticket_test.rb b/test/unit/ticket_test.rb index 96672efb8..6f00d1d2f 100644 --- a/test/unit/ticket_test.rb +++ b/test/unit/ticket_test.rb @@ -455,7 +455,7 @@ class TicketTest < ActiveSupport::TestCase assert( ticket, "ticket created" ) assert_equal( ticket.escalation_time, nil, 'ticket.escalation_time verify' ) - # set sla's for timezone "Europe/Berlin" (+1), so UTC times are 8:00-17:00 + # set sla's for timezone "Europe/Berlin" wintertime (+1), so UTC times are 8:00-17:00 sla = Sla.create( :name => 'test sla 1', :condition => {}, @@ -473,17 +473,16 @@ class TicketTest < ActiveSupport::TestCase :created_by_id => 1, ) ticket = Ticket.find(ticket.id) - assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 12:00:00 UTC', 'ticket.escalation_time verify 1' ) - assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 12:00:00 UTC', 'ticket.first_response_escal_date verify 1' ) - assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 13:00:00 UTC', 'ticket.update_time_escal_date verify 1' ) - assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 14:00:00 UTC', 'ticket.close_time_escal_date verify 1' ) + assert_equal( ticket.escalation_time.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.escalation_time verify 1' ) + assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-03-21 11:30:00 UTC', 'ticket.first_response_escal_date verify 1' ) + assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-03-21 12:30:00 UTC', 'ticket.update_time_escal_date verify 1' ) + assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-03-21 13:30:00 UTC', 'ticket.close_time_escal_date verify 1' ) delete = sla.destroy assert( delete, "sla destroy" ) delete = ticket.destroy assert( delete, "ticket destroy" ) - ticket = Ticket.create( :title => 'some title äöüß', :group => Group.lookup( :name => 'Users'), @@ -498,7 +497,7 @@ class TicketTest < ActiveSupport::TestCase assert( ticket, "ticket created" ) assert_equal( ticket.escalation_time, nil, 'ticket.escalation_time verify' ) - # set sla's for timezone "Europe/Berlin" (+1), so UTC times are 8:00-17:00 + # set sla's for timezone "Europe/Berlin" summertime (+2), so UTC times are 7:00-16:00 sla = Sla.create( :name => 'test sla 1', :condition => {}, @@ -516,16 +515,60 @@ class TicketTest < ActiveSupport::TestCase :created_by_id => 1, ) ticket = Ticket.find(ticket.id) - assert_equal( ticket.escalation_time.gmtime.to_s, '2013-10-21 13:00:00 UTC', 'ticket.escalation_time verify 1' ) - assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-10-21 13:00:00 UTC', 'ticket.first_response_escal_date verify 1' ) - assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-10-21 14:00:00 UTC', 'ticket.update_time_escal_date verify 1' ) - assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-10-21 15:00:00 UTC', 'ticket.close_time_escal_date verify 1' ) + assert_equal( ticket.escalation_time.gmtime.to_s, '2013-10-21 11:30:00 UTC', 'ticket.escalation_time verify 1' ) + assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-10-21 11:30:00 UTC', 'ticket.first_response_escal_date verify 1' ) + assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-10-21 12:30:00 UTC', 'ticket.update_time_escal_date verify 1' ) + assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-10-21 13:30:00 UTC', 'ticket.close_time_escal_date verify 1' ) delete = ticket.destroy assert( delete, "ticket destroy" ) delete = sla.destroy assert( delete, "sla destroy" ) + + ticket = Ticket.create( + :title => 'some title äöüß', + :group => Group.lookup( :name => 'Users'), + :customer_id => 2, + :ticket_state => Ticket::State.lookup( :name => 'new' ), + :ticket_priority => Ticket::Priority.lookup( :name => '2 normal' ), + :created_at => '2013-10-21 06:30:00 UTC', + :updated_at => '2013-10-21 06:30:00 UTC', + :updated_by_id => 1, + :created_by_id => 1, + ) + assert( ticket, "ticket created" ) + assert_equal( ticket.escalation_time, nil, 'ticket.escalation_time verify' ) + + # set sla's for timezone "Europe/Berlin" summertime (+2), so UTC times are 7:00-16:00 + sla = Sla.create( + :name => 'test sla 1', + :condition => {}, + :data => { + "Mon"=>"Mon", "Tue"=>"Tue", "Wed"=>"Wed", "Thu"=>"Thu", "Fri"=>"Fri", "Sat"=>"Sat", "Sun"=>"Sun", + "beginning_of_workday" => "9:00", + "end_of_workday" => "18:00", + }, + :timezone => 'Europe/Berlin', + :first_response_time => 120, + :update_time => 180, + :close_time => 240, + :active => true, + :updated_by_id => 1, + :created_by_id => 1, + ) + ticket = Ticket.find(ticket.id) + assert_equal( ticket.escalation_time.gmtime.to_s, '2013-10-21 09:00:00 UTC', 'ticket.escalation_time verify 1' ) + assert_equal( ticket.first_response_escal_date.gmtime.to_s, '2013-10-21 09:00:00 UTC', 'ticket.first_response_escal_date verify 1' ) + assert_equal( ticket.update_time_escal_date.gmtime.to_s, '2013-10-21 10:00:00 UTC', 'ticket.update_time_escal_date verify 1' ) + assert_equal( ticket.close_time_escal_date.gmtime.to_s, '2013-10-21 11:00:00 UTC', 'ticket.close_time_escal_date verify 1' ) + + delete = sla.destroy + assert( delete, "sla destroy" ) + + delete = ticket.destroy + assert( delete, "ticket destroy" ) + end end diff --git a/test/unit/working_time_test.rb b/test/unit/working_time_test.rb index c03abc95e..4ea11697d 100644 --- a/test/unit/working_time_test.rb +++ b/test/unit/working_time_test.rb @@ -73,6 +73,8 @@ class WorkingTimeTest < ActiveSupport::TestCase ], }, }, + + # test 5 { :start => '2013-02-28 17:00:00', :end => '2013-02-28 23:59:59', @@ -87,10 +89,158 @@ class WorkingTimeTest < ActiveSupport::TestCase 'end_of_workday' => '6:00 pm', }, }, + + # test 6 + { + :start => '2013-02-28 17:00:00', + :end => '2013-03-08 23:59:59', + :diff => 3660, + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 7 + { + :start => '2012-02-28 17:00:00', + :end => '2013-03-08 23:59:59', + :diff => 160860, + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 8 + { + :start => '2013-02-28 17:01:00', + :end => '2013-02-28 18:10:59', + :diff => 61, + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 9 + { + :start => '2013-02-28 18:01:00', + :end => '2013-02-28 18:10:59', + :diff => 0, + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 10 / summertime + { + :start => '2013-02-28 18:01:00', + :end => '2013-02-28 18:10:59', + :diff => 0, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 11 / summertime + { + :start => '2013-02-28 17:01:00', + :end => '2013-02-28 17:10:59', + :diff => 0, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 12 / wintertime + { + :start => '2013-08-29 17:01:00', + :end => '2013-08-29 17:10:59', + :diff => 0, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 13 / summertime + { + :start => '2013-02-28 16:01:00', + :end => '2013-02-28 16:10:59', + :diff => 10, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 14 / wintertime + { + :start => '2013-08-29 16:01:00', + :end => '2013-08-29 16:10:59', + :diff => 0, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, ] tests.each { |test| - TimeCalculation.config( test[:config], nil, test[:start] ) - diff = TimeCalculation.business_time_diff( test[:start], test[:end] ) + diff = TimeCalculation.business_time_diff( test[:start], test[:end], test[:config], test[:timezone] ) assert_equal( diff, test[:diff], 'diff' ) } end @@ -178,6 +328,7 @@ class WorkingTimeTest < ActiveSupport::TestCase }, }, + # test 6 { :start => '2012-12-17 08:00:00', @@ -241,10 +392,112 @@ class WorkingTimeTest < ActiveSupport::TestCase 'end_of_workday' => '6:00 pm', }, }, + + # test 11 / summertime + { + :start => '2013-03-08 21:20:15', + :dest_time => '2013-03-11 09:00:00', + :diff => 120, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 12 / wintertime + { + :start => '2013-09-06 21:20:15', + :dest_time => '2013-09-09 08:00:00', + :diff => 120, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '8:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 13 / wintertime + { + :start => '2013-10-21 06:30:00', + :dest_time => '2013-10-21 09:00:00', + :diff => 120, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '9:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 14 / wintertime + { + :start => '2013-10-21 04:34:15', + :dest_time => '2013-10-21 09:00:00', + :diff => 120, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '9:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 15 / wintertime + { + :start => '2013-10-20 22:34:15', + :dest_time => '2013-10-21 09:00:00', + :diff => 120, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '9:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + + # test 16 / wintertime + { + :start => '2013-10-21 07:00:15', + :dest_time => '2013-10-21 09:00:00', + :diff => 120, + :timezone => 'Europe/Berlin', + :config => { + 'Mon' => true, + 'Tue' => true, + 'Wed' => true, + 'Thu' => true, + 'Fri' => true, + 'beginning_of_workday' => '9:00 am', + 'end_of_workday' => '6:00 pm', + }, + }, + ] tests.each { |test| - TimeCalculation.config( test[:config], nil, test[:start] ) - dest_time = TimeCalculation.dest_time( test[:start] + ' UTC', test[:diff] ) + dest_time = TimeCalculation.dest_time( test[:start] + ' UTC', test[:diff], test[:config], test[:timezone] ) assert_equal( dest_time.gmtime, Time.parse( test[:dest_time] + ' UTC' ), "dest time - #{test[:dest_time].to_s}" ) } end From 9e22395969e917ca3c1e9994d49dc9d8fa8d7738 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 7 Jun 2013 16:01:04 +0200 Subject: [PATCH 7/7] Removed not needed param. --- app/models/ticket.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 3b2ef0182..abf3e2251 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -522,7 +522,7 @@ class Ticket < ApplicationModel } end - def _escalation_calculation_get_sla(time) + def _escalation_calculation_get_sla sla_selected = nil sla_list = Cache.get( 'SLA::List::Active' ) @@ -584,7 +584,7 @@ class Ticket < ApplicationModel end # get sla for ticket - sla_selected = self._escalation_calculation_get_sla(self.created_at) + sla_selected = self._escalation_calculation_get_sla # reset escalation if no sla is set if !sla_selected