+use Scalar::Util qw(weaken);
+
+our @GROUPINGS = (
+ Status => 'Enum', #loc_left_pair
+
+ Queue => 'Queue', #loc_left_pair
+
+ InitialPriority => 'Priority', #loc_left_pair
+ FinalPriority => 'Priority', #loc_left_pair
+ Priority => 'Priority', #loc_left_pair
+
+ Owner => 'User', #loc_left_pair
+ Creator => 'User', #loc_left_pair
+ LastUpdatedBy => 'User', #loc_left_pair
+
+ Requestor => 'Watcher', #loc_left_pair
+ Cc => 'Watcher', #loc_left_pair
+ AdminCc => 'Watcher', #loc_left_pair
+ Watcher => 'Watcher', #loc_left_pair
+
+ Created => 'Date', #loc_left_pair
+ Starts => 'Date', #loc_left_pair
+ Started => 'Date', #loc_left_pair
+ Resolved => 'Date', #loc_left_pair
+ Due => 'Date', #loc_left_pair
+ Told => 'Date', #loc_left_pair
+ LastUpdated => 'Date', #loc_left_pair
+
+ CF => 'CustomField', #loc_left_pair
+);
+our %GROUPINGS;
+
+our %GROUPINGS_META = (
+ Queue => {
+ Display => sub {
+ my $self = shift;
+ my %args = (@_);
+
+ my $queue = RT::Queue->new( $self->CurrentUser );
+ $queue->Load( $args{'VALUE'} );
+ return $queue->Name;
+ },
+ Localize => 1,
+ },
+ Priority => {
+ Sort => 'numeric raw',
+ },
+ User => {
+ SubFields => [grep RT::User->_Accessible($_, "public"), qw(
+ Name RealName NickName
+ EmailAddress
+ Organization
+ Lang City Country Timezone
+ )],
+ Function => 'GenerateUserFunction',
+ },
+ Watcher => {
+ SubFields => [grep RT::User->_Accessible($_, "public"), qw(
+ Name RealName NickName
+ EmailAddress
+ Organization
+ Lang City Country Timezone
+ )],
+ Function => 'GenerateWatcherFunction',
+ },
+ Date => {
+ SubFields => [qw(
+ Time
+ Hourly Hour
+ Date Daily
+ DayOfWeek Day DayOfMonth DayOfYear
+ Month Monthly
+ Year Annually
+ WeekOfYear
+ )], # loc_qw
+ Function => 'GenerateDateFunction',
+ Display => sub {
+ my $self = shift;
+ my %args = (@_);
+
+ my $raw = $args{'VALUE'};
+ return $raw unless defined $raw;
+
+ if ( $args{'SUBKEY'} eq 'DayOfWeek' ) {
+ return $self->loc($RT::Date::DAYS_OF_WEEK[ int $raw ]);
+ }
+ elsif ( $args{'SUBKEY'} eq 'Month' ) {
+ return $self->loc($RT::Date::MONTHS[ int($raw) - 1 ]);
+ }
+ return $raw;
+ },
+ Sort => 'raw',
+ },
+ CustomField => {
+ SubFields => sub {
+ my $self = shift;
+ my $args = shift;
+
+
+ my $queues = $args->{'Queues'};
+ if ( !$queues && $args->{'Query'} ) {
+ require RT::Interface::Web::QueryBuilder::Tree;
+ my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
+ $tree->ParseSQL( Query => $args->{'Query'}, CurrentUser => $self->CurrentUser );
+ $queues = $args->{'Queues'} = $tree->GetReferencedQueues;
+ }
+ return () unless $queues;
+
+ my @res;
+
+ my $CustomFields = RT::CustomFields->new( $self->CurrentUser );
+ foreach my $id (keys %$queues) {
+ my $queue = RT::Queue->new( $self->CurrentUser );
+ $queue->Load($id);
+ next unless $queue->id;
+
+ $CustomFields->LimitToQueue($queue->id);
+ }
+ $CustomFields->LimitToGlobal;
+ while ( my $CustomField = $CustomFields->Next ) {
+ push @res, ["Custom field", $CustomField->Name], "CF.{". $CustomField->id ."}";
+ }
+ return @res;
+ },
+ Function => 'GenerateCustomFieldFunction',
+ Label => sub {
+ my $self = shift;
+ my %args = (@_);
+
+ my ($cf) = ( $args{'SUBKEY'} =~ /^\{(.*)\}$/ );
+ if ( $cf =~ /^\d+$/ ) {
+ my $obj = RT::CustomField->new( $self->CurrentUser );
+ $obj->Load( $cf );
+ $cf = $obj->Name;
+ }
+
+ return 'Custom field [_1]', $cf;
+ },
+ },
+ Enum => {
+ Localize => 1,
+ },
+);
+
+# loc'able strings below generated with (s/loq/loc/):
+# perl -MRT=-init -MRT::Report::Tickets -E 'say qq{\# loq("$_->[0]")} while $_ = splice @RT::Report::Tickets::STATISTICS, 0, 2'
+#
+# loc("Ticket count")
+# loc("Summary of time worked")
+# loc("Total time worked")
+# loc("Average time worked")
+# loc("Minimum time worked")
+# loc("Maximum time worked")
+# loc("Summary of time estimated")
+# loc("Total time estimated")
+# loc("Average time estimated")
+# loc("Minimum time estimated")
+# loc("Maximum time estimated")
+# loc("Summary of time left")
+# loc("Total time left")
+# loc("Average time left")
+# loc("Minimum time left")
+# loc("Maximum time left")
+# loc("Summary of Created-Started")
+# loc("Total Created-Started")
+# loc("Average Created-Started")
+# loc("Minimum Created-Started")
+# loc("Maximum Created-Started")
+# loc("Summary of Created-Resolved")
+# loc("Total Created-Resolved")
+# loc("Average Created-Resolved")
+# loc("Minimum Created-Resolved")
+# loc("Maximum Created-Resolved")
+# loc("Summary of Created-LastUpdated")
+# loc("Total Created-LastUpdated")
+# loc("Average Created-LastUpdated")
+# loc("Minimum Created-LastUpdated")
+# loc("Maximum Created-LastUpdated")
+# loc("Summary of Starts-Started")
+# loc("Total Starts-Started")
+# loc("Average Starts-Started")
+# loc("Minimum Starts-Started")
+# loc("Maximum Starts-Started")
+# loc("Summary of Due-Resolved")
+# loc("Total Due-Resolved")
+# loc("Average Due-Resolved")
+# loc("Minimum Due-Resolved")
+# loc("Maximum Due-Resolved")
+# loc("Summary of Started-Resolved")
+# loc("Total Started-Resolved")
+# loc("Average Started-Resolved")
+# loc("Minimum Started-Resolved")
+# loc("Maximum Started-Resolved")
+
+our @STATISTICS = (
+ COUNT => ['Ticket count', 'Count', 'id'],
+);
+
+foreach my $field (qw(TimeWorked TimeEstimated TimeLeft)) {
+ my $friendly = lc join ' ', split /(?<=[a-z])(?=[A-Z])/, $field;
+ push @STATISTICS, (
+ "ALL($field)" => ["Summary of $friendly", 'TimeAll', $field ],
+ "SUM($field)" => ["Total $friendly", 'Time', 'SUM', $field ],
+ "AVG($field)" => ["Average $friendly", 'Time', 'AVG', $field ],
+ "MIN($field)" => ["Minimum $friendly", 'Time', 'MIN', $field ],
+ "MAX($field)" => ["Maximum $friendly", 'Time', 'MAX', $field ],
+ );
+}
+
+
+foreach my $pair (qw(
+ Created-Started
+ Created-Resolved
+ Created-LastUpdated
+ Starts-Started
+ Due-Resolved
+ Started-Resolved
+)) {
+ my ($from, $to) = split /-/, $pair;
+ push @STATISTICS, (
+ "ALL($pair)" => ["Summary of $pair", 'DateTimeIntervalAll', $from, $to ],
+ "SUM($pair)" => ["Total $pair", 'DateTimeInterval', 'SUM', $from, $to ],
+ "AVG($pair)" => ["Average $pair", 'DateTimeInterval', 'AVG', $from, $to ],
+ "MIN($pair)" => ["Minimum $pair", 'DateTimeInterval', 'MIN', $from, $to ],
+ "MAX($pair)" => ["Maximum $pair", 'DateTimeInterval', 'MAX', $from, $to ],
+ );
+}
+
+our %STATISTICS;
+
+our %STATISTICS_META = (
+ Count => {
+ Function => sub {
+ my $self = shift;
+ my $field = shift || 'id';
+
+ return (
+ FUNCTION => 'COUNT',
+ FIELD => 'id'
+ );
+ },
+ },
+ Simple => {
+ Function => sub {
+ my $self = shift;
+ my ($function, $field) = @_;
+ return (FUNCTION => $function, FIELD => $field);
+ },
+ },
+ Time => {
+ Function => sub {
+ my $self = shift;
+ my ($function, $field) = @_;
+ return (FUNCTION => "$function(?)*60", FIELD => $field);
+ },
+ Display => 'DurationAsString',
+ },
+ TimeAll => {
+ SubValues => sub { return ('Minimum', 'Average', 'Maximum', 'Total') },
+ Function => sub {
+ my $self = shift;
+ my $field = shift;
+ return (
+ Minimum => { FUNCTION => "MIN(?)*60", FIELD => $field },
+ Average => { FUNCTION => "AVG(?)*60", FIELD => $field },
+ Maximum => { FUNCTION => "MAX(?)*60", FIELD => $field },
+ Total => { FUNCTION => "SUM(?)*60", FIELD => $field },
+ );
+ },
+ Display => 'DurationAsString',
+ },
+ DateTimeInterval => {
+ Function => sub {
+ my $self = shift;
+ my ($function, $from, $to) = @_;
+
+ my $interval = $self->_Handle->DateTimeIntervalFunction(
+ From => { FUNCTION => $self->NotSetDateToNullFunction( FIELD => $from ) },
+ To => { FUNCTION => $self->NotSetDateToNullFunction( FIELD => $to ) },
+ );
+
+ return (FUNCTION => "$function($interval)");
+ },
+ Display => 'DurationAsString',
+ },
+ DateTimeIntervalAll => {
+ SubValues => sub { return ('Minimum', 'Average', 'Maximum', 'Total') },
+ Function => sub {
+ my $self = shift;
+ my ($from, $to) = @_;
+
+ my $interval = $self->_Handle->DateTimeIntervalFunction(
+ From => { FUNCTION => $self->NotSetDateToNullFunction( FIELD => $from ) },
+ To => { FUNCTION => $self->NotSetDateToNullFunction( FIELD => $to ) },
+ );
+
+ return (
+ Minimum => { FUNCTION => "MIN($interval)" },
+ Average => { FUNCTION => "AVG($interval)" },
+ Maximum => { FUNCTION => "MAX($interval)" },
+ Total => { FUNCTION => "SUM($interval)" },
+ );
+ },
+ Display => 'DurationAsString',
+ },
+);
+