[Bps-public-commit] RT-Extension-SLA branch, per-queue-timezones, created. 0.05-10-g79e2426

Ruslan Zakirov ruz at bestpractical.com
Fri Apr 20 09:51:30 EDT 2012


The branch, per-queue-timezones has been created
        at  79e2426881e4eb20459c332c6ea6b4b535821999 (commit)

- Log -----------------------------------------------------------------
commit 01c7f3bf39b5259803bb901ab78f8befcaff039c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Feb 29 16:00:07 2012 +0400

    subsitute vars in Test.pm, not in t/utils.pl
    
    utils file is gone

diff --git a/Makefile.PL b/Makefile.PL
index 07119da..99c9689 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -21,7 +21,7 @@ substitute(
         RT_BIN_PATH  => $bin_path,
         RT_SBIN_PATH => $sbin_path,
     },
-    qw(t/utils.pl),
+    qw(lib/RT/Extension/SLA/Test.pm),
 );
 
 WriteAll();
diff --git a/lib/RT/Extension/SLA/Test.pm b/lib/RT/Extension/SLA/Test.pm
index d28cf06..2ed3449 100644
--- a/lib/RT/Extension/SLA/Test.pm
+++ b/lib/RT/Extension/SLA/Test.pm
@@ -2,7 +2,7 @@ use strict;
 use warnings;
 
 ### after: use lib qw(@RT_LIB_PATH@);
-use lib qw(/opt/rt3/local/lib /opt/rt3/lib);
+use lib qw(/opt/rt4/local/lib /opt/rt4/lib);
 
 package RT::Extension::SLA::Test;
 

commit 20f84bdf4dfbd3fe32755d2b07e4aa1658879a3f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Apr 19 18:37:37 2012 +0400

    return more ->Agreement method and always use it

diff --git a/lib/RT/Extension/SLA.pm b/lib/RT/Extension/SLA.pm
index 69cdb0e..1a7b055 100644
--- a/lib/RT/Extension/SLA.pm
+++ b/lib/RT/Extension/SLA.pm
@@ -359,6 +359,8 @@ sub Agreement {
         }
     }
 
+    $res{'BusinessHours'} = $meta->{'BusinessHours'};
+
     return \%res;
 }
 
@@ -369,11 +371,9 @@ sub Due {
     my $agreement = $self->Agreement( %args );
     return undef unless $agreement;
 
-    my $meta = $RT::ServiceAgreements{'Levels'}{ $args{'Level'} };
-
     my $res = $args{'Time'};
     if ( defined $agreement->{'BusinessMinutes'} ) {
-        my $bhours = $self->BusinessHours( $meta->{'BusinessHours'} );
+        my $bhours = $self->BusinessHours( $agreement->{'BusinessHours'} );
         $res = $bhours->add_seconds( $res, 60 * $agreement->{'BusinessMinutes'} );
     }
     $res += 60 * $agreement->{'RealMinutes'}
@@ -386,12 +386,12 @@ sub Starts {
     my $self = shift;
     my %args = ( Level => undef, Time => undef, @_ );
 
-    my $meta = $RT::ServiceAgreements{'Levels'}{ $args{'Level'} };
-    return undef unless $meta;
+    my $agreement = $self->Agreement( %args );
+    return undef unless $agreement;
 
-    return $args{'Time'} if $meta->{'StartImmediately'};
+    return $args{'Time'} if $agreement->{'StartImmediately'};
 
-    my $bhours = $self->BusinessHours( $meta->{'BusinessHours'} );
+    my $bhours = $self->BusinessHours( $agreement->{'BusinessHours'} );
     return $bhours->first_after( $args{'Time'} );
 }
 

commit b62a1c0f912394f806594707cf86c3e417da13fb
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Apr 19 18:39:13 2012 +0400

    new CallBusinessHours method
    
    one entry point into business hours calls

diff --git a/lib/RT/Extension/SLA.pm b/lib/RT/Extension/SLA.pm
index 1a7b055..74cadef 100644
--- a/lib/RT/Extension/SLA.pm
+++ b/lib/RT/Extension/SLA.pm
@@ -326,6 +326,14 @@ sub BusinessHours {
     return $res;
 }
 
+sub CalcBusinessHours {
+    my $self = shift;
+    my $meta = shift;
+    my $method = shift;
+    my $bhours = $self->BusinessHours( $meta->{'BusinessHours'} );
+    return $bhours->$method( @_ );
+}
+
 sub Agreement {
     my $self = shift;
     my %args = ( Level => undef, Type => 'Response', Time => undef, @_ );
@@ -349,8 +357,7 @@ sub Agreement {
     }
 
     if ( $args{'Time'} and my $tmp = $meta->{'OutOfHours'}{ $args{'Type'} } ) {
-        my $bhours = $self->BusinessHours( $meta->{'BusinessHours'} );
-        if ( $bhours->first_after( $args{'Time'} ) != $args{'Time'} ) {
+        if ( $self->CalcBusinessHours( $meta, first_after => $args{'Time'} ) != $args{'Time'} ) {
             foreach ( qw(RealMinutes BusinessMinutes) ) {
                 next unless $tmp->{ $_ };
                 $res{ $_ } ||= 0;
@@ -373,8 +380,10 @@ sub Due {
 
     my $res = $args{'Time'};
     if ( defined $agreement->{'BusinessMinutes'} ) {
-        my $bhours = $self->BusinessHours( $agreement->{'BusinessHours'} );
-        $res = $bhours->add_seconds( $res, 60 * $agreement->{'BusinessMinutes'} );
+        $res = $self->CalcBusinessHours(
+            $agreement,
+            add_seconds => $res, 60 * $agreement->{'BusinessMinutes'},
+        );
     }
     $res += 60 * $agreement->{'RealMinutes'}
         if defined $agreement->{'RealMinutes'};
@@ -391,8 +400,9 @@ sub Starts {
 
     return $args{'Time'} if $agreement->{'StartImmediately'};
 
-    my $bhours = $self->BusinessHours( $agreement->{'BusinessHours'} );
-    return $bhours->first_after( $args{'Time'} );
+    return $self->CalcBusinessHours(
+        $agreement, first_after => $args{'Time'},
+    );
 }
 
 sub GetCustomField {

commit 1721793c586927eea21f297a1909c7c5698e103c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Apr 19 18:41:10 2012 +0400

    provide way to set Timezone in the config
    
    for a level and for a queue

diff --git a/lib/RT/Extension/SLA.pm b/lib/RT/Extension/SLA.pm
index 74cadef..fb3d7c0 100644
--- a/lib/RT/Extension/SLA.pm
+++ b/lib/RT/Extension/SLA.pm
@@ -336,7 +336,14 @@ sub CalcBusinessHours {
 
 sub Agreement {
     my $self = shift;
-    my %args = ( Level => undef, Type => 'Response', Time => undef, @_ );
+    my %args = (
+        Level => undef,
+        Type => 'Response',
+        Time => undef,
+        Ticket => undef,
+        Queue  => undef,
+        @_
+    );
 
     my $meta = $RT::ServiceAgreements{'Levels'}{ $args{'Level'} };
     return undef unless $meta;
@@ -366,6 +373,12 @@ sub Agreement {
         }
     }
 
+    $args{'Queue'} ||= $args{'Ticket'}->QueueObj if $args{'Ticket'};
+    if ( $args{'Queue'} && ref $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name } ) {
+        $res{'Timezone'} = $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name }{'Timezone'};
+    }
+    $res{'Timezone'} ||= $meta->{'Timezone'} || $RT::Timezone;
+
     $res{'BusinessHours'} = $meta->{'BusinessHours'};
 
     return \%res;
@@ -437,8 +450,10 @@ sub GetDefaultServiceLevel {
         else {
             return $args{'Queue'}->SLA if $args{'Queue'}->SLA;
         }
-        if ( $RT::ServiceAgreements{'QueueDefault'} && $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name } ) {
-            return $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name };
+
+        if ( my $info = $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name } ) {
+            return $info unless ref $info;
+            return $info->{'Level'};
         }
     }
     return $RT::ServiceAgreements{'Default'};

commit fce5def2ad781c239403ca51a0a3b1afb8f1d52c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Apr 20 00:54:25 2012 +0400

    fix and improve handling of Starts date
    
    * fix for a problem of recent refactoring.
    
    * Instead of StartImmediately admins can use
      Starts agreement. It has all options like
      other agreements have, but it has default
      value if not defined.

diff --git a/lib/RT/Extension/SLA.pm b/lib/RT/Extension/SLA.pm
index fb3d7c0..ade0d66 100644
--- a/lib/RT/Extension/SLA.pm
+++ b/lib/RT/Extension/SLA.pm
@@ -347,6 +347,16 @@ sub Agreement {
 
     my $meta = $RT::ServiceAgreements{'Levels'}{ $args{'Level'} };
     return undef unless $meta;
+
+    if ( exists $meta->{'StartImmediately'} || !defined $meta->{'Starts'} ) {
+        $meta->{'Starts'} = {
+            delete $meta->{'StartImmediately'}
+                ? ( )
+                : ( BusinessMinutes => 0 )
+            ,
+        };
+    }
+
     return undef unless $meta->{ $args{'Type'} };
 
     my %res;
@@ -359,10 +369,6 @@ sub Agreement {
         return undef;
     }
 
-    if ( defined $meta->{'StartImmediately'} ) {
-        $res{'StartImmediately'} = $meta->{'StartImmediately'};
-    }
-
     if ( $args{'Time'} and my $tmp = $meta->{'OutOfHours'}{ $args{'Type'} } ) {
         if ( $self->CalcBusinessHours( $meta, first_after => $args{'Time'} ) != $args{'Time'} ) {
             foreach ( qw(RealMinutes BusinessMinutes) ) {
@@ -393,10 +399,16 @@ sub Due {
 
     my $res = $args{'Time'};
     if ( defined $agreement->{'BusinessMinutes'} ) {
-        $res = $self->CalcBusinessHours(
-            $agreement,
-            add_seconds => $res, 60 * $agreement->{'BusinessMinutes'},
-        );
+        if ( $agreement->{'BusinessMinutes'} ) {
+            $res = $self->CalcBusinessHours(
+                $agreement,
+                add_seconds => $res,
+                60 * $agreement->{'BusinessMinutes'},
+            );
+        }
+        else {
+            $res = $self->CalcBusinessHours( $agreement, first_after => $res );
+        }
     }
     $res += 60 * $agreement->{'RealMinutes'}
         if defined $agreement->{'RealMinutes'};
@@ -406,16 +418,7 @@ sub Due {
 
 sub Starts {
     my $self = shift;
-    my %args = ( Level => undef, Time => undef, @_ );
-
-    my $agreement = $self->Agreement( %args );
-    return undef unless $agreement;
-
-    return $args{'Time'} if $agreement->{'StartImmediately'};
-
-    return $self->CalcBusinessHours(
-        $agreement, first_after => $args{'Time'},
-    );
+    return $self->Due( @_, Type => 'Starts' );
 }
 
 sub GetCustomField {

commit 6c7862c1f0121b3ff613fe015af76b9543941e18
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Apr 20 01:26:46 2012 +0400

    update docs about Starts date

diff --git a/lib/RT/Extension/SLA.pm b/lib/RT/Extension/SLA.pm
index ade0d66..093b794 100644
--- a/lib/RT/Extension/SLA.pm
+++ b/lib/RT/Extension/SLA.pm
@@ -67,14 +67,14 @@ In this example I<Incident> is the name of the queue, and I<2h> is the name of
 the SLA which will be applied to this queue by default.
 
 Each service level can be described using several options:
-L<StartImmediately|/"StartImmediately (boolean, false)">,
+L<Starts|/"Starts (interval, first business minute)">,
 L<Resolve|/"Resolve and Response (interval, no defaults)">,
 L<Response|/"Resolve and Response (interval, no defaults)">,
 L<KeepInLoop|/"Keep in loop (interval, no defaults)">,
 L<OutOfHours|/"OutOfHours (struct, no default)">
 and L<ServiceBusinessHours|/"Configuring business hours">.
 
-=head2 StartImmediately (boolean, false)
+=head2 Starts (interval, first business minute)
 
 By default when a ticket is created Starts date is set to
 first business minute after time of creation. In other
@@ -84,8 +84,21 @@ be beginning of the next business day.
 
 However, if you provide 24/7 support then you most
 probably would be interested in Starts to be always equal
-to Created time. In this case you can set option
-StartImmediately to a true value.
+to Created time.
+
+Starts option can be used to adjust behaviour. Format
+of the option is the same as format for deadlines which
+described later in details. RealMinutes, BusinessMinutes
+options and OutOfHours modifiers can be used here like
+for any other deadline. For example:
+
+    'standard' => {
+        # give people 15 minutes
+        Starts   => { BusinessMinutes => 15  },
+    },
+
+You can still use old option StartImmediately to set
+Starts date equal to Created date.
 
 Example:
 
@@ -93,9 +106,12 @@ Example:
         StartImmediately => 1,
         Response => { RealMinutes => 30 },
     },
-    'standard' => {
-        StartImmediately => 0, # can be ommited as it's default
-        Response => { BusinessMinutes => 2*60 },
+
+But it's the same as:
+
+    '24/7' => {
+        Starts => { RealMinutes => 0 },
+        Response => { RealMinutes => 30 },
     },
 
 =head2 Resolve and Response (interval, no defaults)

commit 79e2426881e4eb20459c332c6ea6b4b535821999
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Apr 20 17:50:38 2012 +0400

    support per queue timezones

diff --git a/MANIFEST b/MANIFEST
index 62f670e..222021c 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -33,3 +33,4 @@ t/business_hours.t
 t/due.t
 t/queue.t
 t/starts.t
+t/timezone.t
diff --git a/lib/RT/Action/SLA_SetDue.pm b/lib/RT/Action/SLA_SetDue.pm
index 208c2c3..06bf646 100644
--- a/lib/RT/Action/SLA_SetDue.pm
+++ b/lib/RT/Action/SLA_SetDue.pm
@@ -44,12 +44,14 @@ sub Commit {
     );
 
     my $response_due = $self->Due(
+        Ticket => $ticket,
         Level => $level,
         Type => $is_requestor? 'Response': 'KeepInLoop',
         Time => $last_reply->CreatedObj->Unix,
     );
 
     my $resolve_due = $self->Due(
+        Ticket => $ticket,
         Level => $level,
         Type => 'Resolve',
         Time => $ticket->CreatedObj->Unix,
diff --git a/lib/RT/Action/SLA_SetStarts.pm b/lib/RT/Action/SLA_SetStarts.pm
index 9aa2b5a..2b06ca3 100644
--- a/lib/RT/Action/SLA_SetStarts.pm
+++ b/lib/RT/Action/SLA_SetStarts.pm
@@ -34,6 +34,7 @@ sub Commit {
     }
 
     my $starts = $self->Starts(
+        Ticket => $ticket,
         Level => $level,
         Time => $ticket->CreatedObj->Unix,
     );
diff --git a/lib/RT/Extension/SLA.pm b/lib/RT/Extension/SLA.pm
index 093b794..8f7dd1b 100644
--- a/lib/RT/Extension/SLA.pm
+++ b/lib/RT/Extension/SLA.pm
@@ -342,14 +342,6 @@ sub BusinessHours {
     return $res;
 }
 
-sub CalcBusinessHours {
-    my $self = shift;
-    my $meta = shift;
-    my $method = shift;
-    my $bhours = $self->BusinessHours( $meta->{'BusinessHours'} );
-    return $bhours->$method( @_ );
-}
-
 sub Agreement {
     my $self = shift;
     my %args = (
@@ -385,15 +377,7 @@ sub Agreement {
         return undef;
     }
 
-    if ( $args{'Time'} and my $tmp = $meta->{'OutOfHours'}{ $args{'Type'} } ) {
-        if ( $self->CalcBusinessHours( $meta, first_after => $args{'Time'} ) != $args{'Time'} ) {
-            foreach ( qw(RealMinutes BusinessMinutes) ) {
-                next unless $tmp->{ $_ };
-                $res{ $_ } ||= 0;
-                $res{ $_ } += $tmp->{ $_ };
-            }
-        }
-    }
+    $res{'OutOfHours'} = $meta->{'OutOfHours'}{ $args{'Type'} };
 
     $args{'Queue'} ||= $args{'Ticket'}->QueueObj if $args{'Ticket'};
     if ( $args{'Queue'} && ref $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name } ) {
@@ -408,22 +392,42 @@ sub Agreement {
 
 sub Due {
     my $self = shift;
-    my %args = ( Level => undef, Type => undef, Time => undef, @_ );
+    return $self->CalculateTime( @_ );
+}
 
-    my $agreement = $self->Agreement( %args );
+sub Starts {
+    my $self = shift;
+    return $self->CalculateTime( @_, Type => 'Starts' );
+}
+
+sub CalculateTime {
+    my $self = shift;
+    my %args = (@_);
+    my $agreement = $self->Agreement( @_ );
     return undef unless $agreement;
 
+    local $ENV{'TZ'} = $ENV{'TZ'};
+    $ENV{'TZ'} = $agreement->{'Timezone'} if $agreement->{'Timezone'};
+
+    my $bhours = $self->BusinessHours( $agreement->{'BusinessHours'} );
+
     my $res = $args{'Time'};
+
+    if ( $agreement->{'OutOfHours'} && $bhours->first_after( $res ) != $res ) {
+        foreach ( qw(RealMinutes BusinessMinutes) ) {
+            next unless my $mod = $agreement->{'OutOfHours'}{ $_ };
+            ($agreement->{ $_ } ||= 0) += $mod;
+        }
+    }
+
     if ( defined $agreement->{'BusinessMinutes'} ) {
         if ( $agreement->{'BusinessMinutes'} ) {
-            $res = $self->CalcBusinessHours(
-                $agreement,
-                add_seconds => $res,
-                60 * $agreement->{'BusinessMinutes'},
+            $res = $bhours->add_seconds(
+                $res, 60 * $agreement->{'BusinessMinutes'},
             );
         }
         else {
-            $res = $self->CalcBusinessHours( $agreement, first_after => $res );
+            $res = $bhours->first_after( $res );
         }
     }
     $res += 60 * $agreement->{'RealMinutes'}
@@ -432,11 +436,6 @@ sub Due {
     return $res;
 }
 
-sub Starts {
-    my $self = shift;
-    return $self->Due( @_, Type => 'Starts' );
-}
-
 sub GetCustomField {
     my $self = shift;
     my %args = (Ticket => undef, CustomField => 'SLA', @_);
@@ -472,7 +471,7 @@ sub GetDefaultServiceLevel {
 
         if ( my $info = $RT::ServiceAgreements{'QueueDefault'}{ $args{'Queue'}->Name } ) {
             return $info unless ref $info;
-            return $info->{'Level'};
+            return $info->{'Level'} || $RT::ServiceAgreements{'Default'};
         }
     }
     return $RT::ServiceAgreements{'Default'};
diff --git a/t/timezone.t b/t/timezone.t
new file mode 100644
index 0000000..b42039b
--- /dev/null
+++ b/t/timezone.t
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::MockTime qw( :all );
+use RT::Extension::SLA::Test tests => 11;
+my $test = 'RT::Extension::SLA::Test';
+
+my $ru_queue = $test->load_or_create_queue( Name => 'RU' );
+ok $ru_queue && $ru_queue->id, 'created RU queue';
+
+my $us_queue = $test->load_or_create_queue( Name => 'US' );
+ok $us_queue && $ru_queue->id, 'created US queue';
+
+no warnings 'once';
+%RT::ServiceAgreements = (
+    Default => 2,
+    QueueDefault => {
+        RU => { Timezone => 'Europe/Moscow' },
+        US => { Timezone => 'America/New_York' },
+    },
+    Levels  => {
+        '2' => { Resolve => { BusinessMinutes => 60 * 2 } },
+    },
+);
+
+set_absolute_time('2007-01-01T22:00:00Z');
+
+note 'check dates in US queue';
+{
+    my $ticket = RT::Ticket->new($RT::SystemUser);
+    my ($id) = $ticket->Create( Queue => 'US', Subject => 'xxx' );
+    ok( $id, "created ticket #$id" );
+
+    my $start = $ticket->StartsObj->ISO( Timezone => 'utc' );
+    is( $start, '2007-01-01 22:00:00', 'Start date is right' );
+    my $due = $ticket->DueObj->ISO( Timezone => 'utc' );
+    is( $due, '2007-01-02 15:00:00', 'Due date is right' );
+}
+
+note 'check dates in RU queue';
+{
+    my $ticket = RT::Ticket->new($RT::SystemUser);
+    my ($id) = $ticket->Create( Queue => 'RU', Subject => 'xxx' );
+    ok( $id, "created ticket #$id" );
+
+    my $start = $ticket->StartsObj->ISO( Timezone => 'utc' );
+    is( $start, '2007-01-02 06:00:00', 'Start date is right' );
+    my $due = $ticket->DueObj->ISO( Timezone => 'utc' );
+    is( $due, '2007-01-02 08:00:00', 'Due date is right' );
+}
+

-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list