# Type: Input # Category: Task # Description: Shows time spent for some period, project etc # Author: Andriy Lesyuk new Orangutan::Context( response => sub { my ($context, $user, $message) = @_; my @result = ( ); # Remove ending $message =~ s/\?*!*\.*$//; my $dayre = 'Sun(?:day)?|Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|yesterday|today'; my @regexps = ( 'How much time (?:did )?(?:I|([^ ]+?)?) spen(?:d|t)', 'Show (?:('.$dayre.') )?time(?: spent)? (?:of|by) ([^ ]+)', 'Show (?:('.$dayre.') )?time(?: spent)?', 'Show(?: (?:my|([^ ]+?)(?:\'s)?))? (?:('.$dayre.') )?time(?: spent)?' ); # Check base query for (my $i = 0; $i < scalar @regexps; $i++) { if ($message =~ /^$regexps[$i] */i) { my ($day, $username) = (undef, undef); if ($i > 2) { ($day, $username) = ($2, $1); } elsif ($i > 1) { $day = $1; } elsif ($i > 0) { ($day, $username) = ($1, $2); } else { $username = $1; } if (defined($username)) { my $id = $main::query->UserExists($username); if ($id) { push(@result, 1); push(@result, $id); if (defined($day)) { ShowTasks_ParseDay($day, \@result); } $message =~ s/^$regexps[$i] *//i; last; } } else { push(@result, 1); push(@result, undef); if (defined($day)) { ShowTasks_ParseDay($day, \@result); } $message =~ s/^$regexps[$i] *//i; last; } } } if (scalar @result > 0) { if (scalar @result == 2) { ShowTasks_ParsePeriod(\$message, \@result); } if (scalar @result == 2) { ShowTasks_DefaultPeriod(\$message, \@result); } ShowTasks_ParseFilter(\$message, \@result); if ($message !~ /^ *$/) { @result = ( ); } } return @result; }, handler => sub { my ($context, $manager, $item, $userid, $start, $end, $project, $issue, $activity) = @_; my $user; if (!defined($userid) || ($userid == $manager->GetUserID)) { $userid = $manager->GetUserID; $user = $manager; } elsif (!$manager->IsCreator && !$manager->IsManager) { $manager->SendMessage([ 'You have no permission to see this information...', 'Sorry... Maybe next time...', "I can't do this!..", 'Ask the user!' ]); return; } else { $user = $main::users->GetUserID($userid); } if (!defined($start) || !defined($end)) { $manager->SendMessage([ 'Something is wrong with your request... Please fix it!', 'Hm... I guess you made some mistake...', 'Cannot understand the request...' ]); return; } if (defined($issue)) { $manager->SendMessage([ 'Ignoring issue - it is not yet supported (and not sure if it is going to be)!', 'I do not support issue in this request...' ]); } if (defined($activity) && (ref $activity ne 'HASH')) { my $format = Orangutan::Context::Random( 'Activity %s does not exist in project %s...', "I can't find activity %s in project %s..." ); $manager->SendMessage(sprintf($format, $activity, $project->{'name'})); return; } my $projectid = defined($project) ? $project->{'project_id'} : undef; my $activityid = defined($activity) ? $activity->{'id'} : undef; my %items = Orangutan::User::GetWorkHoursDetails(defined($user) ? $user : $userid, $start, $end, $projectid, $activityid); if (scalar keys %items > 0) { my $total = 0; foreach my $pid (keys %items) { my $ptotal = 0; foreach my $aid (keys %{$items{$pid}->{'activities'}}) { $ptotal += $items{$pid}->{'activities'}->{$aid}->{'duration'}; if (!defined($items{$pid}->{'activities'}->{$aid}->{'name'})) { delete($items{$pid}->{'activities'}->{$aid}); } } $items{$pid}->{'duration'} = $ptotal; $total += $ptotal; } my $message; if ($userid == $manager->GetUserID) { $message = Orangutan::Context::Random( 'Total time is', 'You spent' ).' '; } else { $message = Orangutan::Context::Random( 'Total time is', 'User spent' ).' '; } $message .= sprintf('%d:%02d', int($total / 3600), int(($total % 3600) / 60)); if (defined($user)) { my $hours = $user->GetWorkTimeHours; if ($hours) { my $days = scalar $user->GetWorkDays($start->WorkDayStart, $end->WorkDayStart); if ($days) { my $required = $days * ($hours * 3600); $message .= ' ('; $message .= sprintf('%.02f%%', ($total * 100) / $required); $message .= ' '.Orangutan::Context::Random( 'of what it should be', 'of required time' ); if ($required > $total) { $message .= ' (+'; $message .= sprintf('%d:%02d', int(($required - $total) / 3600), int((($required - $total) % 3600) / 60)); $message .= ')'; } $message .= ')'; } } } if (scalar keys %items == 1) { my $pid = (keys %items)[0]; $message .= ' on '.$items{$pid}->{'name'}; $message .= ' ('; my @asort = sort { $items{$pid}->{'activities'}->{$a}->{'name'} cmp $items{$pid}->{'activities'}->{$b}->{'name'} } keys %{$items{$pid}->{'activities'}}; if ((scalar @asort == 1) && ($items{$pid}->{'activities'}->{$asort[0]}->{'duration'} == $items{$pid}->{'duration'})) { $message .= $items{$pid}->{'activities'}->{$asort[0]}->{'name'}; } else { for (my $j = 0; $j < scalar @asort; $j++) { if ($j > 0) { if ($j == $#asort) { $message .= ' and '; } else { $message .= ', '; } } $message .= $items{$pid}->{'activities'}->{$asort[$j]}->{'name'}.' - '; $message .= sprintf('%d:%02d ', int($items{$pid}->{'activities'}->{$asort[$j]}->{'duration'} / 3600), int(($items{$pid}->{'activities'}->{$asort[$j]}->{'duration'} % 3600) / 60)); $message .= sprintf('(%.02f%%)', ($items{$pid}->{'activities'}->{$asort[$j]}->{'duration'} * 100) / $items{$pid}->{'duration'}); } } $message .= ')'; } $message .= ".\n"; if (scalar keys %items > 1) { $message .= ' '; my @psort = sort { $items{$a}->{'name'} cmp $items{$b}->{'name'} } keys %items; for (my $i = 0; $i < scalar @psort; $i++) { if ($i == $#psort) { $message .= ' and '; } elsif ($i != 0) { $message .= ', '; } $message .= sprintf('%d:%02d ', int($items{$psort[$i]}->{'duration'} / 3600), int(($items{$psort[$i]}->{'duration'} % 3600) / 60)); $message .= sprintf('(%.02f%%)', ($items{$psort[$i]}->{'duration'} * 100) / $total); $message .= ' on '.$items{$psort[$i]}->{'name'}; $message .= ' ('; my @asort = sort { $items{$psort[$i]}->{'activities'}->{$a}->{'name'} cmp $items{$psort[$i]}->{'activities'}->{$b}->{'name'} } keys %{$items{$psort[$i]}->{'activities'}}; if ((scalar @asort == 1) && ($items{$psort[$i]}->{'activities'}->{$asort[0]}->{'duration'} == $items{$psort[$i]}->{'duration'})) { $message .= $items{$psort[$i]}->{'activities'}->{$asort[0]}->{'name'}; } else { for (my $j = 0; $j < scalar @asort; $j++) { if ($j > 0) { if ($j == $#asort) { $message .= ' and '; } else { $message .= ', '; } } $message .= $items{$psort[$i]}->{'activities'}->{$asort[$j]}->{'name'}.' - '; $message .= sprintf('%d:%02d ', int($items{$psort[$i]}->{'activities'}->{$asort[$j]}->{'duration'} / 3600), int(($items{$psort[$i]}->{'activities'}->{$asort[$j]}->{'duration'} % 3600) / 60)); $message .= sprintf('(%.02f%%)', ($items{$psort[$i]}->{'activities'}->{$asort[$j]}->{'duration'} * 100) / $items{$psort[$i]}->{'duration'}); } } $message .= ')'; } $message .= '.'; } $manager->SendMessage($message); } else { $manager->SendMessage([ 'You did not work at that time...', 'There were no tasks...' ]); } }, help => { title => 'How can I check how much time did I spend?', question => [ '^(?:(?:How )?(?:(?:can|do) I |to )(?:check|see) )?how much (?:time|hours) '. '(?:did )?I spen[td](?: (?:during|for|at) some period)?\?*!*\.*$', '^(?:How )?(?:(?:can|do) I |to )(?:check|see) (?:my )?(?:work(?:ing)? )?(?:time|hours)(?: spent)?'. '(?: (?:during|for|at) some period)?\?*!*\.*$' ], answer => "Orangutan can show you a very simple report on the time you spent. ". "It can show time for today, yesterday, current week, last month or any other period.\n". "Sample queries:\n". " o Show time from 1st March to 10th March\n". " o How much time did I spend last month?\n". " o How much time did I spend in August?\n". " o Show time spent on last week\n". " o Show time spent on Monday\n". " o Show time for yesterday\n". "You can optionally specify project or activity:\n". " o How much time did I spend (Meetings)?\n". " o Show time on Orangutan\n". "The report can be shown only for days (you can't specify hours)...", weight => 710 }, weight => 90 ); # kate: syntax perl