use strict;
use warnings;
use CGI qw(:standard);
use Date::Simple;
sub NiceDateFormat {
Date::Simple->new($_[0])->format("%d %b %Y");
}
my ($fday,$fmonth,$fyear) = (param('fday'),param('fmonth'),param('fyear'));
my ($tday,$tmonth,$tyear) = (param('tday'),param('tmonth'),param('tyear'));
die &Template("DevMgr/GenericError",{message => 'missing some or all of the FROM date'})
unless ($fday and $fmonth and $fyear);
die &Template("DevMgr/GenericError",{message => 'missing some or all of the TO date'})
unless ($tday and $tmonth and $tyear);
my $start = "$fyear-$fmonth-$fday";
my $end = "$tyear-$tmonth-$tday";
my $s = &db_Staff_On_Site_Between_Two_Dates($start,$end);
my (%days, $hc, @previnits, $thisline, $from, @people, @prevpeople, $prevdate);
push @{$days{$$_[1]}}, $$_[2] for @$s;
# loop through each date (up to the end of range)
# looking for changes in head count
for my $date (sort keys %days) {
@people = sort @{$days{$date}};
# initialise values for the 'previous' day
@prevpeople = @people unless @prevpeople;
$from ||= $date;
$prevdate ||= $date;
if ("@prevpeople" ne "@people") {
# work out who has arrived, who has departed
my (@arriving,@departing);
my %prevpeople = map {$_ => undef} @prevpeople;
my %people = map {$_ => undef} @people;
for (@people) { push @arriving, $_ unless exists $prevpeople{$_}; }
for (@prevpeople) { push @departing, $_ unless exists $people{$_}; }
# then deal with arrivals and departures
my $arriving = @arriving ? &Template("DevMgr/SingleHeadCountArrivalLine",{
date => NiceDateFormat($date),
change => join(", ", sort @arriving)}) : ' ';
my $departing = @departing ? &Template("DevMgr/SingleHeadCountDepartureLine",{
date => NiceDateFormat($prevdate),
change => join(", ", sort @departing)}) : ' ';
# output the headcount as at the previous day
$hc .= &Template("DevMgr/SingleHeadCountLine", {
datefrom => NiceDateFormat($from),
dateto => NiceDateFormat($prevdate),
headcount => scalar(@prevpeople),
staffonsite => join (', ', sort values %{UniqInits(@prevpeople)}),
arriving => $arriving,
departing => $departing
}
);
$from = $date;
@prevpeople = @people;
}
$prevdate = $date;
}
# we drop out of the loop when we hit the end of the range,
# so it is now necessary to output a final line of head count
$hc .= &Template("DevMgr/SingleHeadCountLine", {
datefrom => NiceDateFormat($from),
dateto => NiceDateFormat((reverse sort keys %days)[0]),
headcount => scalar(@people),
staffonsite => join(', ', sort values %{UniqInits(@people)}),
arriving => ' ',
departing => ' '
}
);
print &Template("DevMgr/ShowHeadCount",{ headcount_html => $hc });
####
sub db_Staff_On_Site_Between_Two_Dates {
my ($start,$end) = @_;
die &Template
(
"DevMgr/GenericError",
{message => 'Missing start and/or end date in db_Staff_On_Site_Between_Two_Dates()'}
) unless ($start and $end);
RunSQLReturnArrayRef(
"
declare \@start smalldatetime
declare \@end smalldatetime
set \@start = '$start'
set \@end = '$end'
create table #dates ([date] smalldatetime not null)
declare \@datecount smalldatetime
set \@datecount = \@start
while (\@datecount <= \@end)
begin
insert into #dates values (\@datecount)
set \@datecount = \@datecount + 1
end
select p.person_id,convert(char(8),d.date,112),p.name
from contract c
inner join person p on c.person_id = p.person_id
inner join #dates d -- cartesian join to date range, constrained only by contract DoA and DoL
on d.date between isnull(c.doa,\@start) and isnull(c.dol,\@end)
where p.discipline = 'development'
order by d.date,p.name
drop table #dates
"
);
}
####
sub RunSQLReturnArrayRef {
my $SQL = shift or exit;
my $dbh = Get_database_handle or exit;
my $resultArrayRef=$dbh->selectall_arrayref($SQL);
if ($dbh->err) {
print &Template("DevMgr/GenericError",{message=>"Couldn't prepare statement : $DBI::errstr"});
exit;
}
$dbh->disconnect;
return $resultArrayRef;
}
####
sub UniqInits {
# takes an array of unique names and returns a hashref { 'a man' => [ 'a', 'm'], ... }
my %data;
my $maxnames = 0;
for my $name (@_) {
chomp $name;
my @names = split /[^\w]+/,$name;
$maxnames = @names if @names > $maxnames;
$_ = ucfirst lc $_ for @names;
$data{ "@names" } = \@names;
}
for my $index ( 0 .. $maxnames ) {
for my $person ( keys %data ) {
next if ! $data{$person}[$index];
my $old_name = $data{$person}[$index];
for my $length ( 1 .. length $old_name ) {
$data{$person}[$index] = substr( $old_name, 0, $length );
my $match = 0;
for ( keys %data ) {
next if $_ eq $person || @{$data{$_}} != @{$data{$person}};
my $test_name = $data{$_}[$index];
$data{$_}[$index] = substr( $test_name, 0, $length );
my ($s_name , $s_test) = ("@{$data{$person}}", "@{$data{$_}}");
$data{$_}[$index] = $test_name;
if ( $s_name eq $s_test ) {
$match = 1;
last;
}
}
last if ! $match;
}
}
}
for my $name (keys %data) {
$data{$name} = join '',@{$data{$name}};
}
\%data;
}