<%args>
 $startdate => undef
 $enddate   => undef
 $queues    => undef
</%args>

<& /Elements/Header, Title => $title &>
<& /Tools/Reports/Elements/Tabs, current_tab => 'Tools/Reports/TimeWorkedCustomer.html', Title  => $title &>
<hr>

<%init>
my ($start_date, $end_date, $effective_end_date, $title);

$title = loc('Time worked report');

$start_date = RT::Date->new($session{'CurrentUser'});
$end_date   = RT::Date->new($session{'CurrentUser'}); 

# If we have a value for start date, parse it into an RT::Date object
if ($startdate) {
  $start_date->Set(Format => 'unknown', Value => $startdate);
  # And then get it back as an ISO string for display purposes, in the form field and
  # report header
  $startdate = $start_date->AsString(Format => 'ISO', Timezone => 'server');
}

# Same treatment for end date
if ($enddate) {
  $end_date->Set(Format => 'unknown', Value => $enddate);
  $enddate = $end_date->AsString(Format => 'ISO', Timezone => 'server');

  
</%init> 

<form method="post" action="TimeWorkedCustomer.html">
 <br />
  <&|/l&>Start date</&>:
  <& /Elements/SelectDate, Name => 'startdate', Default => ($startdate) ?  $start_date->AsString(Format => 'ISO', Timezone => 'server') : ''&>
  (report will start from midnight on this day unless you indicate otherwise)
 <br />
  <&|/l&>End date</&>:
  <& /Elements/SelectDate, Name => 'enddate', Default => ($enddate) ?  $end_date->AsString(Format => 'ISO', Timezone => 'server') : ''&>
  (report will -not- be inclusive of this day unless you change the time from midnight)
 <br />
  <&|/l&>Queues</&>:
  <& /Elements/SelectMultiQueue, Name => 'queues', Default => ($queues) ? $queues : ''&>
<& /Elements/Submit&>

</form>


<%perl>
# TimeWorkedReport
# Version 0.04  2009-09-28
#
# Fran Fabrizio, UAB CIS, fran@cis.uab.edu

use strict;

# if we are just getting here and the form values are empty, we are done
if (!$startdate || !$enddate) {
  return;


# get the queue object(s)
my $queuesobj = new RT::Queues($session{CurrentUser});
my ($queuelist, %queuesofinterest);

# The user's choice of queues will come in from the web form in the $queues variable, which is
# mapped to the SELECT field on the web interface for the report.  Unfortunately, if the user
# chooses just one queue, $queues will have a scalar value, but if the user chooses multiple
# queues, it will be an arrayref.  So we need to check for each case and process differently.
#
# What we want to construct is the %queuesofinterest simple lookup hash which defines a key
# that is the queue ID for each queue selected, and the $queuelist string, which is just for 
# displaying the list of queues in the report header
if (ref $queues) {
  # multiple queues selected
  for (@$queues) {
    $queuesobj->Limit(FIELD => "Id", OPERATOR => "=", VALUE => $_, ENTRYAGGREGATOR => "OR");
    $queuesofinterest{$_} = 1;
  } 
  $queuelist = join ", ", map {$_->Name} @{$queuesobj->ItemsArrayRef};
} else {
  my $queue = new RT::Queue;
  $queue->Load(Id => $queues);
  $queuesofinterest{$queues} = 1;
  $queuelist = $queue->Name;
}

# hash to hold statistics
# %stats will be a multilevel hash - first level keys are the usernames, second level keys are 
# the ticket IDs, and for each ticket, we store an anonymous hash with keys Subject and  TimeWorked
# (this implies that a single ticket can live under two+ users if they both worked the ticket)
my %stats;

# Get a new transactions object to hold transaction search results for this ticket
my $trans = new RT::Transactions($session{'CurrentUser'});

# only in the period of interest
$trans->Limit(FIELD => 'Created', OPERATOR => '>', VALUE => $startdate);
$trans->Limit(FIELD => 'Created', OPERATOR => '<', VALUE => $enddate, ENTRYAGGREGATOR =>  'AND');

# now start counting all the TimeTaken by examining transactions associated with this ticket
while (my $tr = $trans->Next) { 

 # did this transaction take any time?  RT records this -either- in TimeTaken column or by 
 # indicating "TimeWorked" in the Field column, depending on how the user inputted the time.
 if ($tr->ObjectType  eq 'RT::Ticket') {
   # Got a hot one - what ticket is this?
   my $t = new RT::Ticket($session{'CurrentUser'});
   $t->Load($tr->ObjectId);

   if (!$t) {
     # unable to retrieve a ticket for this transaction
     # hopefully we don't ever reach here!
     next;
   } else {
     # Is this ticket in a queue we care about?
     if (!$queuesofinterest{$t->Queue}) {
       next;
     } 
   }
        # what customer is this?
   my $c = "";
   my $cfs = $t->CustomFieldValues;
   while (my $cf = $cfs->Next) {
        if ($cf->CustomField == 19) {
      $c = $cf->Content;
        }
   }

  if (!$c) {
     # unable to retrieve a customer for this ticket
     # hopefully we don't ever reach here!
     next;
   }
   
      # we've got some time to account for
   
   # is this the first time this person is charging time to this ticket?
   # if so, add this ticket subject to the data structure
   if (!exists($stats{$c}{$t->id}{Subject})) {
     $stats{$c}{$t->id}{Subject} = $t->Subject;
   }
   
   if ($tr->TimeTaken != 0) {
     # this was a comment or correspondence where the user also added some time worked
     # value of interest appears in Transaction's TimeTaken column
     $stats{$c}{$t->id}{TimeWorked} += $tr->TimeTaken;
   } elsif ($tr->Field && $tr->Field eq 'TimeWorked') {
     # this was a direct update of the time worked field from the Basics or Jumbo ticket update page
     # values of interest appear in Transaction's OldValue and NewValue columns
     # RT does not use the TimeTaken column in this instance.
     $stats{$c}{$t->id}{TimeWorked} += $tr->NewValue - $tr->OldValue;
   } else {
     $stats{$c}{$t->id}{TimeWorked} += 0;
   }
 }
}

# report output starts here
# output:
#  normal user: their own time worked report, most worked ticket to least worked ticket
#  superuser:   everyone's time worked report, in username alpha order, then by most worked to least worked
#  superuser+byticket: most worked ticket first, with everyone's contribution ranked by  biggest contribution to smallest

print "<h2>TIME WORKED REPORT FOR QUEUE(S) " . $queuelist . "</h2>";
print "<h3>Date Range: $startdate TO $enddate</h3>";



  # the existing %stats data structure is perfect for the default report, no data transform  needed
for my $customer (sort keys %stats) {
    
    print "<h3>" . $customer . "</h3>";
    print "<TABLE BORDER=0 CELLSPACING=5>";
    print "<TR><TH>ID</TH><TH>HOURS</TH><TH></TH><TH></TH><TH>SUBJECT</TH></TR>";
    my $totalMinutes = 0;
    for my $tid (sort {$stats{$customer}{$b}{TimeWorked} <=> $stats{$customer}{$a}{TimeWorked}}  keys %{$stats{$customer}}) {
      my $minutes = $stats{$customer}{$tid}{TimeWorked};
      my $subject = $stats{$customer}{$tid}{Subject};
      my $hours = int($minutes/60*100)/100;
      $hours =~ s/\./,/;
#      print "<TR><TD ALIGN=RIGHT>$tid</TD><TD ALIGN=RIGHT>" . sprintf("%.1f",($minutes/60)) . "</TD><TD></TD><TD></TD>" .
#                "<TD><A TARGET=\"_TimeWorked\" HREF=\"/Ticket/Display.html?id=$tid\">$subject</A></TD></TR>";
      print "<TR><TD ALIGN=RIGHT>$tid</TD><TD ALIGN=RIGHT>$hours</TD><TD></TD><TD></TD>" .
                "<TD><A TARGET=\"_TimeWorked\" HREF=\"/Ticket/Display.html?id=$tid\">$subject</A></TD></TR>";
      $totalMinutes += $minutes;
    }
    print "<TR><TD ALIGN=RIGHT><B>TOTAL</B></TD><TD ALIGN=RIGHT><B>" . sprintf("%.1f",($totalMinutes/60)) . "</B></TD><TD></TD><TD></TD><TD></TD></TR>";
    print "</TABLE>";
  }

##### helper functions below

sub form_date_string {
 # expects seven input params - year, month, day, hour, minute, second, offset
 my $year = $_[0] - 1900;
 my $mon = $_[1] - 1;
 my $day = $_[2];
 my $hour = $_[3] ? $_[3] : 0;
 my $min = $_[4] ? $_[4] : 0;
 my $sec = $_[5] ? $_[5] : 0;
 my $offset = $_[6] ? $_[6] : 0;

 # convert to seconds since epoch, then adjust for the $offset, which is also in seconds
 # we do this so we don't have to do fancy date arithmetic - we can just subtract one seconds
 # value from the other seconds value
 my $starttime = timelocal($sec,$min,$hour,$day,$mon,$year) - $offset;
 
 # convert back to component parts now that we've adjusted for offset
 # this gives us the components which represent the GMT time for the local time that was entered
 # on the command line
 ($sec,$min,$hour,$day,$mon,$year) = localtime($starttime);

 # format the date string, padding with zeros if needed
 return sprintf("%04d-%02d-%02d %02d:%02d:%02d", ($year+1900), ($mon+1), $day, $hour, $min, $sec);
}

</%perl>