[Rt-commit] rt branch, 4.4/timeworked-per-user, created. rt-4.2.11-131-gedd13c0
Todd Wade
todd at bestpractical.com
Tue Aug 11 07:33:03 EDT 2015
The branch, 4.4/timeworked-per-user has been created
at edd13c0c291fb9701358df0929c19406d1b00c2b (commit)
- Log -----------------------------------------------------------------
commit 081f4d1b967d8162d9709cb85499db181763c83b
Author: Todd Wade <todd at bestpractical.com>
Date: Wed Jul 8 01:01:12 2015 -0400
add a way for tests to get ticket pages besides the display page
diff --git a/lib/RT/Test/Web.pm b/lib/RT/Test/Web.pm
index 1f44d3c..718744d 100644
--- a/lib/RT/Test/Web.pm
+++ b/lib/RT/Test/Web.pm
@@ -159,13 +159,14 @@ sub logout {
sub goto_ticket {
my $self = shift;
my $id = shift;
+ my $view = shift || 'Display';
unless ( $id && int $id ) {
Test::More::diag( "error: wrong id ". defined $id? $id : '(undef)' );
return 0;
}
my $url = $self->rt_base_url;
- $url .= "Ticket/Display.html?id=$id";
+ $url .= "Ticket/${ view }.html?id=$id";
$self->get($url);
unless ( $self->status == 200 ) {
Test::More::diag( "error: status is ". $self->status );
commit 890234b21945660d22c1f10a0d3e7628cd07bead
Author: Todd Wade <todd at bestpractical.com>
Date: Wed Jul 8 01:02:45 2015 -0400
Automatically update the timeworked field of a ticket's parent tickets
Increment parent tickets TimeWorked field when a child ticket TimeWorked
is set or upated via scrip.
For new installs, default to the behavior enabled. For upgrades, install
the scrip disabled.
diff --git a/etc/initialdata b/etc/initialdata
index dd1daf5..981c955 100644
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -886,3 +886,34 @@ Hour: { $SubscriptionObj->SubValue('Hour') }
},
},
);
+
+# timeworked related functionality that was cored from extensions
+
+push @ScripActions => (
+ {
+ Name => 'Update Parent TimeWorked', # loc
+ Description => 'Update Parent TimeWorked', # loc
+ ExecModule => 'UpdateParentTimeWorked',
+ },
+);
+
+
+push @ScripConditions => (
+ {
+ Name => 'On TimeWorked Change', # loc
+ Description => 'When TimeWorked Change', # loc
+ ApplicableTransTypes => 'Any',
+ ExecModule => 'TimeWorkedChange',
+ },
+);
+
+push @Scrips => (
+ {
+ Description => 'On TimeWorked Change Update Parent TimeWorked',
+ ScripCondition => 'On TimeWorked Change',
+ ScripAction => 'Update Parent TimeWorked',
+ Template => 'Blank',
+ },
+);
+
+1;
diff --git a/etc/upgrade/4.4.0rc1/content b/etc/upgrade/4.4.0rc1/content
new file mode 100644
index 0000000..c06c83f
--- /dev/null
+++ b/etc/upgrade/4.4.0rc1/content
@@ -0,0 +1,29 @@
+ at ScripActions = (
+ {
+ Name => 'Update Parent TimeWorked', # loc
+ Description => 'Update Parent TimeWorked', # loc
+ ExecModule => 'UpdateParentTimeWorked',
+ },
+);
+
+
+ at ScripConditions = (
+ {
+ Name => 'On TimeWorked Change', # loc
+ Description => 'When TimeWorked Change', # loc
+ ApplicableTransTypes => 'Any',
+ ExecModule => 'TimeWorkedChange',
+ },
+);
+
+ at Scrips = (
+ {
+ Description => 'On TimeWorked Change Update Parent TimeWorked',
+ ScripCondition => 'On TimeWorked Change',
+ ScripAction => 'Update Parent TimeWorked',
+ Template => 'Blank',
+ Disabled => 1,
+ },
+);
+
+1;
diff --git a/lib/RT/Action/UpdateParentTimeWorked.pm b/lib/RT/Action/UpdateParentTimeWorked.pm
new file mode 100644
index 0000000..e91479a
--- /dev/null
+++ b/lib/RT/Action/UpdateParentTimeWorked.pm
@@ -0,0 +1,43 @@
+use strict;
+use warnings;
+
+package RT::Action::UpdateParentTimeWorked;
+use base 'RT::Action';
+
+sub Prepare {
+ my $self = shift;
+ my $ticket = $self->TicketObj;
+ return 0 unless $ticket->MemberOf->Count;
+ return 1;
+}
+
+sub Commit {
+ my $self = shift;
+ my $ticket = $self->TicketObj;
+ my $txn = $self->TransactionObj;
+
+ my $parents = $ticket->MemberOf;
+ my $time_worked = $txn->TimeTaken
+ || ( $txn->NewValue - $txn->OldValue );
+
+ while ( my $parent = $parents->Next ) {
+ my $parent_ticket = $parent->TargetObj;
+ my $original_actor = RT::CurrentUser->new( $txn->Creator );
+ my $actor_parent_ticket = RT::Ticket->new( $original_actor );
+ $actor_parent_ticket->Load( $parent_ticket->Id );
+ unless ( $actor_parent_ticket->Id ) {
+ RT->Logger->error("Unable to load ".$parent_ticket->Id." as ".$txn->Creator->Name);
+ return 0;
+ }
+ my ( $ret, $msg ) = $actor_parent_ticket->_Set(
+ Field => 'TimeWorked',
+ Value => $parent_ticket->TimeWorked + $time_worked,
+ );
+ unless ($ret) {
+ RT->Logger->error(
+ "Failed to update parent ticket's TimeWorked: $msg");
+ }
+ }
+}
+
+1;
diff --git a/lib/RT/Condition/TimeWorkedChange.pm b/lib/RT/Condition/TimeWorkedChange.pm
new file mode 100644
index 0000000..f6d9322
--- /dev/null
+++ b/lib/RT/Condition/TimeWorkedChange.pm
@@ -0,0 +1,19 @@
+use strict;
+use warnings;
+
+package RT::Condition::TimeWorkedChange;
+use base 'RT::Condition';
+
+sub IsApplicable {
+ my $self = shift;
+ my $txn = $self->TransactionObj;
+ return 1 if $txn->TimeTaken;
+ return 1
+ if $txn->Type eq 'Set'
+ && $txn->Field eq 'TimeWorked'
+ && ( $txn->NewValue - $txn->OldValue );
+ return 0;
+}
+
+
+1;
diff --git a/t/web/ticket_timeworked.t b/t/web/ticket_timeworked.t
new file mode 100644
index 0000000..91cccdc
--- /dev/null
+++ b/t/web/ticket_timeworked.t
@@ -0,0 +1,76 @@
+use strict;
+use warnings;
+use RT::Test tests => undef;
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok( $m->login, "Logged in" );
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+ok( $queue->id, "loaded the General queue" );
+
+my ( $child1, $child2 ) = RT::Test->create_tickets(
+ { Queue => 'General' },
+ { Subject => 'child ticket 1', },
+ { Subject => 'child ticket 2', },
+);
+
+my ( $child1_id, $child2_id ) = ( $child1->id, $child2->id );
+my $parent_id; # id of the parent ticket
+
+diag "add ticket links of type MemberOf base"; {
+ my $ticket = RT::Test->create_ticket(
+ Queue => 'General',
+ Subject => "timeworked parent",
+ );
+ my $id = $parent_id = $ticket->id;
+
+ $m->goto_ticket($id);
+ $m->follow_link_ok( { text => 'Links' }, "Followed link to Links" );
+
+ ok( $m->form_with_fields("MemberOf-$id"), "found the form" );
+ $m->field( "MemberOf-$id", "$child1_id $child2_id" );
+
+ $m->submit;
+
+ $m->content_like(
+ qr{"DeleteLink-.*?ticket/$child1_id-MemberOf-"},
+ "base for MemberOf: has child1 ticket",
+ );
+ $m->content_like(
+ qr{"DeleteLink-.*?ticket/$child2_id-MemberOf-"},
+ "base for MemberOf: has child2 ticket",
+ );
+
+ $m->goto_ticket($id);
+ $m->content_like( qr{$child1_id:.*?\[new\]}, "has active ticket", );
+}
+
+my @updates = ({
+ id => $child1_id,
+ view => 'Modify',
+ field => 'TimeWorked',
+ form => 'TicketModify',
+ title => "Modify ticket #$child1_id",
+}, {
+ id => $child2_id,
+ view => 'Update',
+ field => 'UpdateTimeWorked',
+ form => 'TicketUpdate',
+ title => "Update ticket #$child2_id (child ticket 2)",
+});
+
+
+foreach my $update ( @updates ) {
+ $m->goto_ticket( $update->{id}, $update->{view} );
+ $m->title_is( $update->{title}, 'have child ticket page' );
+ ok( $m->form_name( $update->{form} ), 'found the form' );
+ $m->field( $update->{field}, 90 );
+ $m->submit_form( button => 'SubmitTicket' );
+}
+
+$m->goto_ticket( $parent_id );
+$m->title_is( "#$parent_id: timeworked parent");
+$m->content_like( qr{180 minutes}, "found expected minutes in parent ticket" );
+
+undef $m;
+done_testing();
\ No newline at end of file
commit edd13c0c291fb9701358df0929c19406d1b00c2b
Author: Todd Wade <todd at bestpractical.com>
Date: Wed Jul 8 22:00:06 2015 -0400
Break out the time worked on a ticket per user
Under the total time worked in the ticket basics on the ticket display
page, display the time that each user has worked on the ticket. A scrip
is used to cache the time worked per user in a ticket attribute.
For new installs, default to the behavior enabled. For upgrades, install
the scrip disabled.
diff --git a/etc/initialdata b/etc/initialdata
index 981c955..405df0a 100644
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -895,6 +895,11 @@ push @ScripActions => (
Description => 'Update Parent TimeWorked', # loc
ExecModule => 'UpdateParentTimeWorked',
},
+ {
+ Name => 'Update User TimeWorked', # loc
+ Description => 'Update User TimeWorked', # loc
+ ExecModule => 'UpdateUserTimeWorked',
+ },
);
@@ -914,6 +919,10 @@ push @Scrips => (
ScripAction => 'Update Parent TimeWorked',
Template => 'Blank',
},
+ {
+ Description => 'On TimeWorked Change Update User TimeWorked',
+ ScripCondition => 'On TimeWorked Change',
+ ScripAction => 'Update User TimeWorked',
+ Template => 'Blank',
+ },
);
-
-1;
diff --git a/etc/upgrade/4.4.0rc1/content b/etc/upgrade/4.3.8/content
similarity index 57%
rename from etc/upgrade/4.4.0rc1/content
rename to etc/upgrade/4.3.8/content
index c06c83f..e1949b5 100644
--- a/etc/upgrade/4.4.0rc1/content
+++ b/etc/upgrade/4.3.8/content
@@ -1,13 +1,21 @@
- at ScripActions = (
+use warnings;
+use strict;
+
+our @ScripActions = (
{
Name => 'Update Parent TimeWorked', # loc
Description => 'Update Parent TimeWorked', # loc
ExecModule => 'UpdateParentTimeWorked',
},
+ {
+ Name => 'Update User TimeWorked', # loc
+ Description => 'Update User TimeWorked', # loc
+ ExecModule => 'UpdateUserTimeWorked',
+ },
);
- at ScripConditions = (
+our @ScripConditions = (
{
Name => 'On TimeWorked Change', # loc
Description => 'When TimeWorked Change', # loc
@@ -16,7 +24,7 @@
},
);
- at Scrips = (
+our @Scrips = (
{
Description => 'On TimeWorked Change Update Parent TimeWorked',
ScripCondition => 'On TimeWorked Change',
@@ -24,6 +32,13 @@
Template => 'Blank',
Disabled => 1,
},
+ {
+ Description => 'On TimeWorked Change Update User TimeWorked',
+ ScripCondition => 'On TimeWorked Change',
+ ScripAction => 'Update User TimeWorked',
+ Template => 'Blank',
+ Disabled => 1,
+ },
);
1;
diff --git a/lib/RT/Action/UpdateParentTimeWorked.pm b/lib/RT/Action/UpdateParentTimeWorked.pm
index e91479a..6904f55 100644
--- a/lib/RT/Action/UpdateParentTimeWorked.pm
+++ b/lib/RT/Action/UpdateParentTimeWorked.pm
@@ -1,9 +1,72 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
+# <sales at bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
use strict;
use warnings;
package RT::Action::UpdateParentTimeWorked;
use base 'RT::Action';
+=head1 NAME
+
+RT::Action::UpdateParentTimeWorked - RT's scrip action to set/update the time
+worked on a parent ticket when a child ticket's TimeWorked is added to.
+
+=head1 DESCRIPTION
+
+This action is used as an action for the 'On TimeWorked Change' condition.
+
+When it fires it finds a ticket's parent tickets and increments the time on
+those tickets along with the built in behavior of incrementing the TimeWorked
+on the current ticket.
+
+=cut
+
sub Prepare {
my $self = shift;
my $ticket = $self->TicketObj;
@@ -40,4 +103,10 @@ sub Commit {
}
}
+=head1 AUTHOR
+
+Best Practical Solutions, LLC E<lt>modules at bestpractical.comE<gt>
+
+=cut
+
1;
diff --git a/lib/RT/Action/UpdateUserTimeWorked.pm b/lib/RT/Action/UpdateUserTimeWorked.pm
new file mode 100644
index 0000000..ddd221b
--- /dev/null
+++ b/lib/RT/Action/UpdateUserTimeWorked.pm
@@ -0,0 +1,95 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
+# <sales at bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
+use strict;
+use warnings;
+
+package RT::Action::UpdateUserTimeWorked;
+use base 'RT::Action';
+
+=head1 NAME
+
+RT::Action::UpdateUserTimeWorked - RT's scrip action to set/update the time
+worked for a user each time they log time worked on a ticket
+
+=head1 DESCRIPTION
+
+This action is used as an action for the 'On TimeWorked Change' condition.
+
+When it fires, a ticket attribute stores the amount of time the user updating
+the ticket worked on it.
+
+=cut
+
+sub Prepare {
+ return 1;
+}
+
+sub Commit {
+ my $self = shift;
+ my $ticket = $self->TicketObj;
+ my $txn = $self->TransactionObj;
+
+ my $time_worked_attr = $ticket->FirstAttribute('TimeWorked');
+ # if the attribute is not defined, we will initialize it in the callback,
+ # so no need to handle it here
+ if ( $time_worked_attr ) {
+ my $time_worked = $time_worked_attr->Content;
+ $time_worked->{ $txn->CreatorObj->Name } += $txn->TimeTaken
+ || $txn->NewValue - $txn->OldValue;
+ $time_worked_attr->SetContent( $time_worked );
+ }
+}
+
+=head1 AUTHOR
+
+Best Practical Solutions, LLC E<lt>modules at bestpractical.comE<gt>
+
+=cut
+
+1;
diff --git a/lib/RT/Condition/TimeWorkedChange.pm b/lib/RT/Condition/TimeWorkedChange.pm
index f6d9322..469cb2b 100644
--- a/lib/RT/Condition/TimeWorkedChange.pm
+++ b/lib/RT/Condition/TimeWorkedChange.pm
@@ -1,9 +1,69 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
+# <sales at bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
use strict;
use warnings;
package RT::Condition::TimeWorkedChange;
use base 'RT::Condition';
+=head1 NAME
+
+RT::Condition::TimeWorkedChange - RT's scrip condition that fires when the
+TimeWorked field has a value at form submission.
+
+=head1 DESCRIPTION
+
+This condition is true when the transaction has a TimeTaken value or the
+TimeWorked field is being updated.
+
+=cut
+
sub IsApplicable {
my $self = shift;
my $txn = $self->TransactionObj;
@@ -15,5 +75,10 @@ sub IsApplicable {
return 0;
}
+=head1 AUTHOR
+
+Best Practical Solutions, LLC E<lt>modules at bestpractical.comE<gt>
+
+=cut
1;
diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 193b2c2..3f288e0 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -3978,6 +3978,10 @@ our %SCRUBBER_ALLOWED_ATTRIBUTES = (
}ix,
dir => qr/^(rtl|ltr)$/i,
lang => qr/^\w+(-\w+)?$/,
+
+ # timeworked per user attributes
+ 'data-ticket-id' => 1,
+ 'data-ticket-class' => 1,
);
our %SCRUBBER_RULES = ();
diff --git a/share/html/Ticket/Elements/ShowBasics b/share/html/Ticket/Elements/ShowBasics
index 546f581..9c37eb3 100644
--- a/share/html/Ticket/Elements/ShowBasics
+++ b/share/html/Ticket/Elements/ShowBasics
@@ -62,11 +62,26 @@
% }
% $m->callback( %ARGS, CallbackName => 'AfterTimeEstimated', TicketObj => $Ticket );
% if ($Ticket->TimeWorked) {
- <tr class="time worked">
+ <tr class="time worked sum">
<td class="label"><&|/l&>Worked</&>:</td>
<td class="value"><& ShowTime, minutes => $Ticket->TimeWorked &></td>
</tr>
% }
+% if ( keys %$time_worked ) {
+<tr class="time worked by-user">
+ <td class="label"><&|/l&>Users</&>:</td>
+ <td>
+ <table>
+% for my $user ( keys %$time_worked ) {
+ <tr>
+ <td class="value"><% $user %>:</td>
+ <td class="value"><& /Ticket/Elements/ShowTime, minutes => $time_worked->{$user} &></td>
+ </tr>
+% }
+ </table>
+ </td>
+</tr>
+% }
% $m->callback( %ARGS, CallbackName => 'AfterTimeWorked', TicketObj => $Ticket );
% if ($Ticket->TimeLeft) {
<tr class="time left">
@@ -95,3 +110,43 @@
$Ticket => undef
$UngroupedCFs => 0
</%ARGS>
+<%init>
+my $time_worked;
+if ( $Ticket->TimeWorked ) {
+ my $time_worked_attr = $Ticket->FirstAttribute('TimeWorked');
+
+ if ($time_worked_attr) {
+ $time_worked = $time_worked_attr->Content;
+ } else {
+ $time_worked = {};
+ my $transactions = $Ticket->Transactions;
+ $transactions->Limit(
+ FIELD => 'Type',
+ VALUE => 'Set',
+ SUBCLAUSE => 'timeworked',
+ );
+
+ $transactions->Limit(
+ FIELD => 'Field',
+ VALUE => 'TimeWorked',
+ SUBCLAUSE => 'timeworked',
+ ENTRYAGGREGATOR => 'AND',
+ );
+
+ $transactions->Limit(
+ FIELD => 'TimeTaken',
+ VALUE => 0,
+ OPERATOR => '>',
+ SUBCLAUSE => 'timeworked',
+ ENTRYAGGREGATOR => 'OR',
+ );
+
+ while ( my $txn = $transactions->Next ) {
+ $time_worked->{ $txn->CreatorObj->Name } += $txn->TimeTaken
+ || $txn->NewValue - $txn->OldValue;
+ }
+ $Ticket->SetAttribute( Name => 'TimeWorked', Content => $time_worked );
+ }
+}
+
+</%init>
diff --git a/share/static/css/base/ticket-form.css b/share/static/css/base/ticket-form.css
index 15ce713..358ae4f 100644
--- a/share/static/css/base/ticket-form.css
+++ b/share/static/css/base/ticket-form.css
@@ -81,3 +81,8 @@ iframe.richtext-editor {
position: absolute;
margin-left: 0.5em;
}
+
+form.add_time_worked {
+ display: inline;
+ margin-left: 10px;
+}
diff --git a/share/static/js/util.js b/share/static/js/util.js
index 6cc2acf..46ae5bd 100644
--- a/share/static/js/util.js
+++ b/share/static/js/util.js
@@ -501,3 +501,28 @@ jQuery(function() {
jQuery('select.chosen').chosen({ width: '20em', placeholder_text_multiple: ' ', no_results_text: ' ', search_contains: true });
AddAttachmentWarning();
});
+
+// timeworked javascript
+jQuery( function () {
+ jQuery('a[data-ticket-class=add_time_worked]').click( function () {
+ var form = jQuery(this).siblings('form');
+ form.find('input[name=TimeWorked]').focus();
+ return false;
+ });
+
+ jQuery('form.add_time_worked.template input[name=ActivityDate]').val(
+ jQuery('input[name=ActivityDate]:first').val());
+
+ var form_template = jQuery('form.add_time_worked.template');
+ jQuery('a[data-ticket-class=add_time_worked]').each( function ( index, e ) {
+ var id = jQuery(this).attr('data-ticket-id');
+ var form = form_template.clone();
+ form.insertAfter(e);
+ form.find('input[name=Ticket]').val(id);
+ form.removeClass('hidden template');
+ });
+
+ jQuery('input[name=ActivityDate]:first').change( function() {
+ jQuery(this).closest('form').submit();
+ });
+});
diff --git a/t/web/ticket_timeworked.t b/t/web/ticket_timeworked.t
index 91cccdc..4737bda 100644
--- a/t/web/ticket_timeworked.t
+++ b/t/web/ticket_timeworked.t
@@ -17,7 +17,7 @@ my ( $child1, $child2 ) = RT::Test->create_tickets(
my ( $child1_id, $child2_id ) = ( $child1->id, $child2->id );
my $parent_id; # id of the parent ticket
-diag "add ticket links of type MemberOf base"; {
+diag "add ticket links for timeworked tests"; {
my $ticket = RT::Test->create_ticket(
Queue => 'General',
Subject => "timeworked parent",
@@ -45,32 +45,106 @@ diag "add ticket links of type MemberOf base"; {
$m->content_like( qr{$child1_id:.*?\[new\]}, "has active ticket", );
}
-my @updates = ({
- id => $child1_id,
- view => 'Modify',
- field => 'TimeWorked',
- form => 'TicketModify',
- title => "Modify ticket #$child1_id",
-}, {
- id => $child2_id,
- view => 'Update',
- field => 'UpdateTimeWorked',
- form => 'TicketUpdate',
- title => "Update ticket #$child2_id (child ticket 2)",
-});
-
-
-foreach my $update ( @updates ) {
- $m->goto_ticket( $update->{id}, $update->{view} );
- $m->title_is( $update->{title}, 'have child ticket page' );
- ok( $m->form_name( $update->{form} ), 'found the form' );
- $m->field( $update->{field}, 90 );
- $m->submit_form( button => 'SubmitTicket' );
+diag "adding timeworked values for child tickets"; {
+ my $user_a = RT::Test->load_or_create_user(
+ Name => 'user_a', Password => 'password',
+ );
+ ok $user_a && $user_a->id, 'loaded or created user';
+
+ my $user_b = RT::Test->load_or_create_user(
+ Name => 'user_b', Password => 'password',
+ );
+ ok $user_b && $user_b->id, 'loaded or created user';
+
+ ok( RT::Test->set_rights(
+ { Principal => $user_a, Right => [qw(SeeQueue ShowTicket ModifyTicket CommentOnTicket)] },
+ { Principal => $user_b, Right => [qw(SeeQueue ShowTicket ModifyTicket CommentOnTicket)] },
+ ), 'set rights');
+
+
+ my @updates = ({
+ id => $child1_id,
+ view => 'Modify',
+ field => 'TimeWorked',
+ form => 'TicketModify',
+ title => "Modify ticket #$child1_id",
+ time => 45,
+ user => 'user_a',
+ }, {
+ id => $child2_id,
+ view => 'Modify',
+ field => 'TimeWorked',
+ form => 'TicketModify',
+ title => "Modify ticket #$child2_id",
+ time => 35,
+ user => 'user_a',
+ }, {
+ id => $child2_id,
+ view => 'Update',
+ field => 'UpdateTimeWorked',
+ form => 'TicketUpdate',
+ title => "Update ticket #$child2_id (child ticket 2)",
+ time => 90,
+ user => 'user_b',
+ });
+
+ foreach my $update ( @updates ) {
+ my $agent = RT::Test::Web->new;
+ ok $agent->login($update->{user}, 'password'), 'logged in as user';
+ $agent->goto_ticket( $update->{id}, $update->{view} );
+ $agent->title_is( $update->{title}, 'have child ticket page' );
+ ok( $agent->form_name( $update->{form} ), 'found the form' );
+ $agent->field( $update->{field}, $update->{time} );
+ $agent->submit_form( button => 'SubmitTicket' );
+ }
+}
+
+diag "checking parent ticket for expected timeworked data"; {
+ $m->goto_ticket( $parent_id );
+ $m->title_is( "#$parent_id: timeworked parent");
+ $m->content_like(
+ qr{(?s)Worked:.+?value">2\.8 hours \(170 minutes\)},
+ "found expected total TimeWorked in parent ticket"
+ );
+ $m->content_like(
+ qr{(?s)user_a:.+?value">1\.3 hours \(80 minutes\)},
+ "found expected user_a TimeWorked in parent ticket"
+ );
+ $m->content_like(
+ qr{(?s)user_b:.+?value">1\.5 hours \(90 minutes\)},
+ "found expected user_b TimeWorked in parent ticket"
+ );
+}
+
+diag "checking child ticket 1 for expected timeworked data"; {
+ $m->goto_ticket( $child1_id );
+ $m->title_is( "#$child1_id: child ticket 1");
+ $m->content_like(
+ qr{(?s)Worked:.+?value">45 minutes},
+ "found expected total TimeWorked in child ticket 1"
+ );
+ $m->content_like(
+ qr{(?s)user_a:.+?value">45 minutes},
+ "found expected user_a TimeWorked in child ticket 1"
+ );
}
-$m->goto_ticket( $parent_id );
-$m->title_is( "#$parent_id: timeworked parent");
-$m->content_like( qr{180 minutes}, "found expected minutes in parent ticket" );
+diag "checking child ticket 2 for expected timeworked data"; {
+ $m->goto_ticket( $child2_id );
+ $m->title_is( "#$child2_id: child ticket 2");
+ $m->content_like(
+ qr{(?s)Worked:.+?value">2\.1 hours \(125 minutes\)},
+ "found expected total TimeWorked in child ticket 2"
+ );
+ $m->content_like(
+ qr{(?s)user_a:.+?value">35 minutes},
+ "found expected user_a TimeWorked in child ticket 2"
+ );
+ $m->content_like(
+ qr{(?s)user_b:.+?value">1\.5 hours \(90 minutes\)},
+ "found expected user_b TimeWorked in child ticket 2"
+ );
+}
undef $m;
-done_testing();
\ No newline at end of file
+done_testing();
-----------------------------------------------------------------------
More information about the rt-commit
mailing list