#!/usr/bin/perl # Copyright 2001-2009 Leslie Richardson # This file is part of Open Admin for Schools. use DBI; use CGI qw\escape unescape\; use Date::Business; use Time::JulianDay; use Number::Format qw(round); #use strict; %lex = ('Attendance Scan' => 'Attendance Scan', 'Attendance' => 'Attendance', 'Today' => 'Today', 'Yesterday' => 'Yesterday', 'This Week' => 'This Week', 'Last Week' => 'Last Week', 'Start Date' => 'Start Date', 'End Date' => 'End Date', 'Date' => 'Date', 'Select by Dates' => 'Select by Dates', 'Reason' => 'Reason', 'Points' => 'Points', 'Select Scanning Date(s)' => 'Select Scanning Date(s)', 'Missing Start Date or End Date' => 'Missing Start Date or End Date', 'Missing Date' => 'Missing Date', 'Add Discipline Entries and Form Letters' => 'Add Discipline Entries and Form Letters', 'Click on' => 'Click on', 'to see' => 'to see', 'Name' => 'Name', 'Discipline' => 'Discipline', 'Record' => 'Record', 'Missing Values for ' => 'Missing Values for ', 'Record Added' => 'Record Added', 'Attendance - exceeded limit for subject' => 'Attendance - exceeded limit for subject', 'Cannot open' => 'Cannot open', 'No form letter found for' => 'No form letter found for', 'for' => 'for', 'Student' => 'Student', 'Subject' => 'Subject', 'Previous' => 'Previous', 'Current' => 'Current', 'Total' => 'Total', 'Discipline Form Letters' => 'Discipline Form Letters', 'Main' => 'Main', 'Attendance' => 'Attendance', 'View Log File' => 'View Log File', 'Days' => 'Days', 'Trigger' => 'Trigger', 'Event' => 'Event', 'No trigger values found in admin.conf' => 'No trigger values found in admin.conf', 'Write Discipline Records?' => 'Write Discipline Records?', 'Result' => 'Result', 'Error' => 'Error', 'Checked' => 'Checked', ); my $self = 'attscan.pl'; eval require "../../etc/admin.conf"; if ( $@ ) { print $lex{Error}. " $@
\n"; die $lex{Error}. " $@\n"; } my $q = CGI->new; print $q->header( -charset, $charset ); my %arr = $q->Vars; my $checked; if ( $arr{checked} ) { delete $arr{checked}; $checked = q{checked="checked"}; } my $dsn = "DBI:$dbtype:dbname=$dbase"; my $dbh = DBI->connect($dsn,$user,$password); $dbh->{mysql_enable_utf8} = 1; # Display page header print "$doctype\n$lex{'Attendance Scan'}\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "$chartype\n[ $lex{Attendance} ]\n"; print "

$lex{'Attendance Scan'}

\n"; #foreach my $key (keys %arr) { print "K: $key V: $arr{$key}
\n"; } # Passed either $arr{date} or $arr{startdate} and $arr{enddate} # if date is could be today, yesterday, thisweek, or lastweek. # if today or yesterday, set $singleDay; other cases set startdate and enddate. # Set Dates - FIX THIS AFTER DONE; remove stuff we don't need. #($sec, $min, $hour, $mday, $mon, $year, $wday, # $yday, $iddst) = localtime(time); my @tim = localtime(time); my $year = $tim[5] + 1900; my $month = $tim[4] + 1; my $day = $tim[3]; my $jd = julian_day($year,$month,$day); if (length($month) == 1){ $month = "0".$month;} if (length($day) == 1){ $day = "0".$day;} #my $currdate = "$dow["$tim[6]+1"], $month[$month] $tim[3], $year"; my $today = "$year-$month-$day"; my $currdate = "$year-$month-$day"; $currsdate = "$year$month$day"; $currdate1 = "$month[$month] $day, $year"; $dow = day_of_week($jd + 1); # a number from 0 (Sunday) to 6 (Saturday) # Branch to different pages if ( not $arr{flag} ) { showStartPage(); } elsif ($arr{flag} == 2) { delete $arr{flag}; writeRecords(); } else { # and continue on below... delete $arr{flag}; } # Now setup date range values. my ($singleday, $startdate, $enddate, $prevday); if ( $arr{date} ) { if ($arr{date} eq $lex{Today}) { $singleday = $currdate; } elsif ($arr{date} eq $lex{Yesterday}) { # Figure out yesterday using Date::Business my $btoday = new Date::Business(); $btoday->prevb(); $singleday = $btoday->image(); $singleday = substr($singleday,0,4).'-'.substr($singleday,4,2).'-'.substr($singleday,6,2); } elsif ( $arr{date} eq $lex{'This Week'} ) { # set startdate and enddate my $mondayjd = $jd - ($tim[6]-1); #This will now give Monday of this week. my $fridayjd = $mondayjd + 4; my ($y,$m,$d) = inverse_julian_day($mondayjd); if (length($m) == 1){ $m = "0".$m;} if (length($d) == 1){ $d = "0".$d;} $startdate = "$y-$m-$d"; my ($y,$m,$d) = inverse_julian_day($fridayjd); if (length($m) == 1){ $m = "0".$m;} if (length($d) == 1){ $d = "0".$d;} $enddate = "$y-$m-$d"; } elsif ($arr{date} eq $lex{'Last Week'}) { my $mondayjd = $jd - ($tim[6]-1); #This will now give Monday of this week. my $mondayjd = $mondayjd - 7; # last monday. my $fridayjd = $mondayjd + 4; # last friday. my ($y,$m,$d) = inverse_julian_day($mondayjd); if (length($m) == 1){ $m = "0".$m;} if (length($d) == 1){ $d = "0".$d;} $startdate = "$y-$m-$d"; my ($y,$m,$d) = inverse_julian_day($fridayjd); if (length($m) == 1){ $m = "0".$m;} if (length($d) == 1){ $d = "0".$d;} $enddate = "$y-$m-$d"; } else { # an error... no match print $lex{'Missing Date'},"
\n"; die; } } elsif ($arr{startdate} and $arr{enddate}) { $startdate = $arr{startdate}; $enddate = $arr{enddate}; } else { # another error... no date or no startdate/enddate print $lex{'Missing Start Date or End Date'},"
\n"; die; } # display date range(s) Set startdate/enddate if singleday; set # prevday. Prevday is one day before the single day value or the day # before the start of the date range. It is used as the enddate for # searches for previous attendance values. We have 2 blocks of time: # 1) Start of Year to Prev Day. # 2) Single Day (1 day) or Startdate and Enddate (a block of days). if ( $singleday ) { print "",$lex{Date},": $singleday
\n"; $startdate = $singleday; $enddate = $singleday; } else { print "",$lex{'Start Date'},": $startdate\n"; print "",$lex{'End Date'},": $enddate
\n"; } # Set $prevday from $startdate my $tmpdate = $startdate; $tmpdate =~ s/-//g; $sdate = new Date::Business(DATE => $tmpdate); $sdate->prevb(); $prevday = $sdate->image(); $prevday = substr($prevday,0,4).'-'.substr($prevday,4,2).'-'.substr($prevday,6,2); #foreach my $key (keys %arr) { print "K: $key V: $arr{$key}
\n"; } my $sth; # Find the students that have attendance records in this date range if ( $singleday ) { # A single day query $sth = $dbh->prepare("select distinct studentid from attend where absdate = '$singleday' order by studentid"); } elsif ( $startdate ) { # We select a date range $sth = $dbh->prepare("select distinct studentid from attend where to_days(attend.absdate) >= to_days('$startdate') and to_days(attend.absdate) <= to_days('$enddate') order by studentid"); } else { # a mistake print $lex{'Missing Date'}, "
\n"; print "\n"; exit; } $sth->execute; if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; } my $sth1 = $dbh->prepare("select lastname, firstname from studentall where studnum = ?"); my @studnum; while ( my $sn = $sth->fetchrow ) { # Get Name $sth1->execute( $sn ); if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr;} my ($lastname, $firstname) = $sth1->fetchrow; push @studnum, "$lastname:$firstname:$sn"; } # Map reason to points in points hash. for (0..$#attend) { $points{$attend[$_]} = $points[$_]; } print "
\n"; print "\n"; print "
\n"; print "\n"; print $lex{'Write Discipline Records?'}; print "
\n"; print "\n"; print "\n"; print '\n"; my $sth2 = $dbh->prepare("select distinct subjsec from attend where studentid = ? group by subjsec"); my $sth3 = $dbh->prepare("select description from subject where subjsec = ?"); my $sth4 = $dbh->prepare("select id, infraction, date from discipline where userid = ? and to_days(date) > to_days('$schoolstart') order by date"); foreach my $rec ( sort @studnum ) { my ($lastname, $firstname, $sn) = split /:/, $rec; # Get subjects $sth2->execute( $sn ); if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; } my $first = 1; while ( my $subj = $sth2->fetchrow ) { my $currpoints = calcPointsSubject($sn,$startdate,$enddate, $subj); if ( not $currpoints ) { next; } $sth3->execute($subj); my $desc = $sth3->fetchrow; my $prevpoints = calcPointsSubject($sn,$schoolstart,$prevday, $subj); my $totalpoints = $currpoints + $prevpoints; # Find the triggers, if any. They are keys in %trigger hash. my $triggerpoint; foreach my $trigger (sort keys %trigger) { if ( $prevpoints < $trigger and $totalpoints >= $trigger ) { $triggerpoint = $trigger; } } print ""; if ( $first ) { print "\n"; $first = 0; } else { print "\n"; } print "\n"; print "\n"; if ( $triggerpoint ) { print "\n"; } else { print "\n"; } } # Get Discpline Events $sth4->execute( $sn ); my $first = 1; while ( my ( $id,$infraction,$date ) = $sth4->fetchrow ) { if ( $first ) { print ""; print "\n\n"; } print "
". $lex{'Click on'}. ' '. $lex{Name}. ' '; print $lex{'to see'}. ' '. $lex{Discipline}. ' '. $lex{Record}; print ", ". $lex{Subject}. ' '. $lex{'to see'}. ' '.$lex{Attendance}; print q{ }. $lex{Record}. "
'. $lex{Student}. ''. $lex{Subject}. ''; print $lex{Previous}. '
'. $lex{Points}; print '
'. $lex{Current}. '
'. $lex{Points}. '
'. $lex{Total}; print '
'. $lex{Points}. "
". $lex{Result}. "
"; print "$firstname $lastname$firstname $lastname$desc ($subj)$prevpoints$currpoints$totalpoints\n"; print "$trigger{$triggerpoint} ($triggerpoint points)
". $lex{Discipline}. q{ }; $first = 0; } print "$infraction - $date | \n"; } print "
"; print "\n"; print $lex{'Write Discipline Records?'}; print " \n"; print "
\n"; #----------------- sub showStartPage { #----------------- print "
\n"; print "\n"; print "
"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
$lex{'Select Scanning Date(s)'}
". $lex{'Start Date'}. ""; print "\n"; print "
". $lex{'End Date'}. ""; print "
"; print "
". $lex{Checked}; print "
\n"; print "
\n"; # Print Reasons and Points per Reason print "
\n"; print "\n"; print "\n"; for (0..$#attend) { print "\n"; } print "
". $lex{Reason}. "". $lex{Points}. "
$attend[$_]$points[$_]
\n"; # Print Discipline Events and Trigger Points if ( %trigger ) { print "
"; print "\n"; print "\n"; foreach my $key (sort {$a <=> $b} keys %trigger) { print "\n"; } print "
". $lex{Discipline}. "
". $lex{Event}. "
"; print $lex{Trigger}. "
"; print $lex{Points}. "
$trigger{$key}$key
\n"; } else { print "

". $lex{'No trigger values found in admin.conf'}. "

\n"; } print "\n"; print "\n"; print "\n"; exit; } #------------- sub calcPoints { #------------- # calculate points for student for date range (inclusive). Lookups are in admin.conf my ( $studnum, $start, $end ) = @_; my $points; my $sth = $dbh->prepare("select distinct reason, count(reason) from attend where studentid = ? and to_days(absdate) >= to_days('$start') and to_days(absdate) <= to_days('$end') group by subjsec, reason"); $sth->execute( $studnum ); if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; } while ( my ( $reason, $rcount ) = $sth->fetchrow ) { $points += ($points{$reason} * $rcount); # %points hash maps reason to points; created in main. } return $points; } #-------------------- sub calcPointsSubject { #-------------------- # calculate points for student for date range (inclusive) in a # subject. Lookups are in admin.conf my ($studnum, $start, $end, $subjsec) = @_; my $points; my $sth = $dbh->prepare("select distinct reason, count(reason) from attend where studentid = ? and subjsec = ? and to_days(absdate) >= to_days('$start') and to_days(absdate) <= to_days('$end') group by subjsec, reason"); $sth->execute( $studnum, $subjsec ); if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; } while ( my ( $reason, $rcount) = $sth->fetchrow) { $points += ( $points{$reason} * $rcount ); # %points hash maps reason to points; created in main. } return $points; } #--------------- sub writeRecords { #--------------- # Write the discipline attendance records and form # letters. Provide links to download the form letters pdf (as # normal) and also links to edit the discipline records created. my $disciplineWrite; if ( $arr{disciplinewrite} ) { $disciplineWrite = 1; } delete $arr{disciplinewrite}; my $sth1 = $dbh->prepare("select lastname, firstname, grade from studentall where studnum = ?"); my $sth2 = $dbh->prepare("select description from subject where subjsec = ?"); # Open a TeX file for creation; use a template... my $logfile = "pdflog$$.txt"; my $shortname = "attdisc$$"; my $filename = "$shortname.tex"; open(TEX,">$filename") || die "Can't open tex file"; printTeXStart(); # Setup the start of the file. my %studsort = (); foreach my $key ( keys %arr ) { # loop through all kids my ( $points, $studnum, $subjsec, $totalpoints ) = split /:/,$key; $sth1->execute( $studnum ); my ( $lastname, $firstname ) = $sth1->fetchrow; my $newkey = "$lastname$firstname$studnum"; $studsort{ $newkey } = $key; } #Original: foreach my $key ( keys %arr ) { # loop through all kids foreach my $newkey ( sort keys %studsort ) { # loop through all kids my $key = $studsort{$newkey}; my ( $points, $studnum, $subjsec, $totalpoints ) = split /:/,$key; if ( not $points or not $studnum or not $subjsec ) { print $lex{'Missing Values for '}, $key, "
\n"; } # Find their name and grade (for ppd) $sth1->execute( $studnum ); if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; } my ( $lastname, $firstname, $grade ) = $sth1->fetchrow; # Get Subject description $sth2->execute( $subjsec ); if ( $DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; } my $desc = $sth2->fetchrow; # Get their formletter template my $templatename = $formletter{$points}; if ( not $templatename ){ print $lex{'No form letter found for'}, " $firstname $lastname \n"; print $lex{'for'}, " $desc ($subjsec)\n", die; } unless (open (FH,"<", "../../template/forms/$templatename")) { print $lex{'Cannot open'}. " form - $!\n"; die $lex{'Cannot open'}. " form - $!\n"; } my $text; { local $/; $text = ; close FH;} my $description = $lex{'Attendance - exceeded limit for subject'}." $desc ($subjsec)"; # Write the discipline record for attendance problems if ( $disciplineWrite ) { # checkbox on previous page my $sth = $dbh->prepare("insert into discipline ( date, userid, infraction, description ) values ( now(), ?, ?, ? )"); if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; } $sth->execute( $studnum, $trigger{$points}, $description ); if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; } # Notify user of written record. print $lex{Discipline}. q{ }. $lex{'Record Added'}; print ": $firstname $lastname $desc ($subjsec)
\n"; } my $absentDivider; if ( $points[0] ) { # defined in admin.conf; normally 3 for abs unexcused $absentDivider = $points[0]; } else { # fallback; not necessarily correct value $absentDivider = 1; } # total points would be bigger if trigger point already # passed, but pass on larger value to the form letter; # separate points needed for trigger above since used as index # into array, etc. if ( $totalpoints > $points ) { $points = $totalpoints; } my $periods = round( $points / $absentDivider, 0 ); my $classesmissed = $periods; #print "CM: $classesmissed Points: $points Periods: $periods
\n"; my $periodsPerDay; if ( not $grade or not $g_ppd{$grade} ) { $periodsPerDay = 1; } else { $periodsPerDay = $g_ppd{$grade}; } my $days = round( $periods / $periodsPerDay ); %rec = (date => $currdate1, studentname => "$firstname $lastname", subject => "$desc ($subjsec)", daysmissed => "$days ". $lex{Days}, schoollogo => "\\includegraphics[width=3in]{../../etc/schoollogo.jpg}", schoolname => $schoolname, schooladdr1 => $schooladdr1, schooladdr2 => $schooladdr2, schooladdr3 => $schooladdr3, schoolcity => $schoolcity, schoolprov => $schoolprov, schoolpcode => $schoolpcode, schoolphone => $schoolphone, schoolfax => $schoolfax, schoolemail => $schoolemail, classesmissed => $classesmissed ); my $template = $text; # Now put replacement text back in. $template =~ s{\<\#(.*?)\#\>} { exists($rec{$1}) ? $rec{$1} : $1 }gsex; #print "Template is
$template
\n"; print TEX $template,"\n"; print TEX "\\newpage\n\n"; } print TEX "\\end{document}"; close TEX; system("$pdflatex $filename > $logfile"); system("mv $shortname.pdf $downloaddir"); system("mv $logfile $downloaddir"); system("rm $shortname.*"); #print "
"; print "

"; print ""; print $lex{'Discipline Form Letters'}. "

\n"; print "

[ ". $lex{Main}. " | "; print "". $lex{Attendance}. " | \n"; print "". $lex{'View Log File'}. " ]

\n"; print "\n"; exit; } # End of writeRecords #---------------- sub printTeXStart { #---------------- my $papersize; if ( $defaultpapersize ) { $papersize = $defaultpapersize; } else { $papersize = 'letterpaper'; } print TEX "\\documentclass[12pt,$papersize,oneside]{article} \\usepackage{array,colortbl,graphicx,inputenc} $a_latex_header \\renewcommand{\\familydefault}{\\sfdefault} \\pagestyle{empty} \\setlength{\\textwidth}{6.5in} \\setlength{\\textheight}{10in} \\setlength{\\hoffset}{-0.5in} \\setlength{\\voffset}{-0.5in} \\setlength{\\headsep}{10pt} \\setlength{\\headheight}{14pt} \\setlength{\\topmargin}{0pt} \\setlength{\\parindent}{0pt} \\setlength{\\tabcolsep}{5pt} \\setlength{\\extrarowheight}{3pt} \\thispagestyle{empty} \\pagestyle{empty} \\begin{document}\n"; } # End of printTeXStart