#! /usr/bin/perl # Copyright 2001-2011 Leslie Richardson # This file is part of Open Admin for Schools. # Open Admin for Schools is free software; you can redistribute it # and/or modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # This is a DUAL RUN script. It runs in /tcgi and also /cgi/repcard. # Outline: This prints a full xtab report for a single grade/class. All # objectives are perpendicular. # Outline: 1) Find all the students in the group (class/section/grade). # 2) Loop through all eval records for the selected term to find all # of the subjects. # 3) Load all subjects into a 2D array. Baseref->Arrayptr1->[0], etc. # Order by subjsec, name of subject, then any objectives next (start # at array index 2) my %lex = ('Year End' => 'Year End', 'Report' => 'Report', 'Missing' => 'Missing', 'Group' => 'Group', 'Grade' => 'Grade', 'Homeroom' => 'Homeroom', 'View/Download' => 'View/Download', 'Teacher' => 'Teacher', 'Principal' => 'Principal', 'View Log File' => 'View Log File', 'Report Card' => 'Report Card', 'Main' => 'Main', 'Missing' => 'Missing', 'Short Subject Descriptions' => 'Short Subject Descriptions', 'Note' => 'Note', 'Page' => 'Page', 'Trm' => 'Trm', 'Term' => 'Term', 'No Student(s) Found' => 'No Student(s) Found', 'Y' => 'Y', 'Error' => 'Error', 'Continue' => 'Continue', 'Select by' => 'Select by', 'Paper Size' => 'Paper Size', 'Letter' => 'Letter', 'A4' => 'A4', 'Legal' => 'Legal', ); my $self = 'rptsummarkend.pl'; use DBI; use CGI; use Date::Business; use Cwd; use Number::Format qw(:all); # Constants # These two settings control the vertical height of the header. my $objectivelength = 36; # number of characters to truncate objectives to. my $offset = "25mm"; # Strut length in print_header fn. my $maxstudents = 36; # Number of student rows per page; if you adjust above, # this may have to change also. my $maxlegalcols = 16; # maximum number of columns per printed page. my $maxlettercols = 16; # Get current dir so know what path for config files. my $configpath; if (getcwd() =~ /tcgi/){ # we are in tcgi $configpath = '..'; # go back one to get to etc. } else { $configpath = '../..'; # go back two to get to etc. } eval require "$configpath/etc/admin.conf"; if ( $@ ) { print $lex{Error}. ": $@
\n"; die $lex{Error}. ": $@\n"; } eval require "$configpath/etc/repcard.conf"; if ( $@ ) { print $lex{Error}. ": $@
\n"; die $lex{Error}. ": $@\n"; } eval require "$configpath/lib/liblatex.pl"; if ( $@ ) { print $lex{Error}. ": $@
\n"; die $lex{Error}. ": $@\n"; } eval require "$configpath/lib/libattend.pl"; if ( $@ ) { print $lex{Error}. ": $@
\n"; die $lex{Error}. ": $@\n"; } # Get current dir so know what CSS to display; if (getcwd() =~ /tcgi/){ # we are in tcgi $css = $tchcss; } my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $iddst) = localtime(time); $year = $year + 1900; $mon++; $wday++; my $currlongdate = "$dow[$wday], $month[$mon] $mday, $year"; my $currdate = "$month[$mon] $year"; # $mday removed if (length($mon) == 1){ $mon = '0'.$mon;} if (length($mday) == 1){ $mday = '0'.$mday;} my $currsdate = "$year-$mon-$mday"; my $dsn = "DBI:$dbtype:dbname=$dbase"; $dbh = DBI->connect($dsn,$user,$password); $dbh->{mysql_enable_utf8} = 1; # Leave $dbh alone since libraries depend on it. my $q = new CGI; print $q->header( -charset, $charset ); my %arr = $q->Vars; # Print the Page Header my $title = "$lex{'Year End'} $lex{Report}"; print "$doctype\n$title $chartype\n\n"; print "[ $lex{Main} \n"; if ( not (getcwd() =~ tcgi) ) { # not running in tcgi print "| ". $lex{'Report Card'}. "\n"; } print " ]
\n"; print "

$title

\n"; if ( not $arr{page} ) { showStartPage(); } else { delete $arr{page}; } # Now passed: group and group_value my $group_value = $arr{group_value}; my $group; if ( $arr{group} eq 'grade' ) { $group = 'grade'; } else { $group = 'homeroom'; } #foreach my $key (keys %arr ) { print "K:$key V:$arr{$key}
\n"; } # Set paper size. my ( $papersize, $textheight, $textwidth, $maxcolumns ); if ( $arr{papersize} eq 'legal'} ) { $textwidth = $g_legalpaper_textwidth; $textheight = $g_legalpaper_textheight; $papersize = 'legalpaper'; $maxcolumns = $maxlegalcols; } elsif ( $arr{papersize} eq 'a4' ) { $textwidth = $g_a4paper_textwidth; $textheight = $g_a4paper_textheight; $papersize = 'a4paper'; $maxcolumns = $maxlettercols; } else { # Letter $textwidth = $g_letterpaper_textwidth; $textheight = $g_letterpaper_textheight; $papersize = 'letterpaper'; $maxcolumns = $maxlettercols; } # $schoolstart and $schoolend defined in the admin.conf config file. my $schoolDaysInYear = calcTermDays($schoolstart,$schoolend); #print "School Days: $schoolDaysInYear\n"; # Must be passed a grade or homeroom. if ( not $group_value ) { print "

$lex{Missing} $lex{Group}

\n"; print "\n"; exit; } if ( $arr{maxstudents} ) { $maxlines = $arr{maxstudents}; } else { $maxlines = $maxstudents; } # If not set, get the current term. my $term; if ( not $term ) { open(TERM, "$configpath/etc/term") || die "Can't find the term number!"; $term = ; close TERM; } # Get Students First; by grade or homeroom. my $sth = $dbh->prepare("select studnum, lastname, firstname, grade from student where $group = ? order by lastname, firstname"); # Note: $grade here can actually be homeroom also... $sth->execute( $group_value ); if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; } $studary = $sth->fetchall_arrayref; my $studcount = $#$studary + 1; #print "Student Count: $studcount \n"; if ( $studcount < 1 ) { print "

". $lex{'No Student(s) Found'}. "

\n"; print "\n"; exit; } # Setup TEX Code my $shortname = "summarkend$$"; my $filename = "$shortname.tex"; open(TEX,">$filename") || die "Can't open tex file"; # removed landscape here... print TEX "\\documentclass[10pt,$papersize]{article} \\usepackage{array,rotating,inputenc} $a_latex_header \\pagestyle{empty} \\setlength{\\textwidth}{$textwidth} \\setlength{\\textheight}{$textheight} \\setlength{\\hoffset}{-13mm} \\setlength{\\voffset}{-13mm} \\setlength{\\topmargin}{0in} \\setlength{\\headheight}{0mm} \\setlength{\\headsep}{0mm} \\setlength{\\parindent}{0mm} \\setlength{\\evensidemargin}{0mm} \\setlength{\\oddsidemargin}{0mm} \\setlength{\\tabcolsep}{1pt} \\setlength{\\extrarowheight}{4pt}\n"; print TEX "\\begin{document}\\begin{center}\n"; if ($divisionname){ print TEX "{\\huge\\sf $divisionname}\n\n"; } else { print TEX "{\\huge\\sf $schoolname}\n\n"; } print TEX "{\\bf\\large $lex{'Year End'} $lex{Report}}\n\n"; print TEX "{\\bf\\large "; if ( $group eq 'grade' ) { print TEX $lex{Grade}; } else { print TEX $lex{Homeroom}; } print TEX " $group_value -- $schoolyear}"; print TEX "\\end{center}\n\n"; # Collect all the subjects taken by this group of students. foreach my $studref ( @$studary ) { # Note: $studref is a reference/pointer. # Select subject/section by grade and term my $subary; my $sth1 = $dbh->prepare("select distinct subjcode from eval where term = '$term' and eval.studnum = '$$studref[0]'"); $sth1->execute; if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; } $subary = $sth1->fetchall_arrayref; foreach my $subjsec ( @{$subary} ) { my ($subj,$section) = split /-/,$$subjsec[0]; # We have to put ONE version of subject in IF grade if ($tempsubject{$subj} and $group eq $lex{Grade} ){ # If already in tempsubject and grade is group, don't do # Nothin'. } else { # Act normal; put subject/section into array. $subjects{$$subjsec[0]} = 1; $tempsubject{$subj}= 1; } } } my $objcount = 0; # Count Objectives... my $subjectbreakpoint = 0; # Add their subjects (and objectives) to a 2D array called fullsubjary # Each row in array has subjsec, and then objectives. foreach my $subjsec ( sort keys %subjects ){ # Skip Unwanted Subjects my ($subjcode, $dud) = split(/-/, $subjsec); if ( $r_SupressSubject{$subjsec} or $r_SupressSubject{$subjcode} or $r_AdditionalComments{$subjsec} or $r_AdditionalComments{$subjcode} ) { next; } # Get Subject Information; pull in full subject record $sth = $dbh->prepare("select * from subject where subjsec = ?"); $sth->execute( $subjsec ); if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; } my @subject = $sth->fetchrow; @subject = latex_filter( @subject ); my $objref = (); push @$objref, $subjsec; # If no short description, then long versions used. if ( not $subject[37] ){ if ( length( $subject[2] ) > $objectivelength ) { $subject[10] = substr( $subject[2],0,$objectivelength); # trunc full desc } else { $subject[10] = $subject[2]; } $subject[10] = "{\\bf $subject[10]} "; $missingflag = 1; # used below on HTML output. } else { $subject[10] = "{\\bf $subject[37]} "; #~~Short Description } for ( my $i=10;$i<11;$i++){ if ($subject[$i]){ # Truncate the objective length. if ( length( $subject[$i] ) > $objectivelength){ $subject[$i] = substr($subject[$i],0,$objectivelength); } push @$objref,$subject[$i]; $objcount++; } } #print "OBJ:$objcount BP:$subjectbreakpoint
\n"; if ($objcount > $maxcolumns){ # push subjbreakpoint into subject break array push @subjbreakary,$subjectbreakpoint; $objcount = 0; # reset objective count } # This is incremented AFTER the test for too large. $subjectbreakpoint++; # objcount is reset, but subjectbreakpoint keeps going/growing. push @fullsubjary, $objref; # Make 2D array } # Test print full subject array. #foreach my $subj ( @fullsubjary ) { # print "
Sub: $$subj[0] \n"; #} # Now get break points for subjects and students. # print "Subject Break points: ", @subjbreakary, "
\n"; for my $i( 0..($studcount - 1) ) { if ($i % ($maxstudents - 1) == 0 and $i != 0){ # Minus 1 since we use array index (1 less) push @studbreakary,$i; } } push @studbreakary, $studcount; # put in the end... #print "
Student Break Array: ",@studbreakary,"
\n"; my $firstflag = 1; $pagecount = 1; $currstud = 0; foreach $studbreak ( @studbreakary ) { $prevstud = $currstud; $currstud = $studbreak; $currsubj = 0; foreach $subjbreak (@subjbreakary){ $prevsubj = $currsubj; $currsubj = $subjbreak; &print_page($prevstud,$currstud -1,$prevsubj,$currsubj - 1,$pagecount); $pagecount++; print TEX "\\newpage\n\n"; } if (not $firstflag){ print TEX "\\newpage\n\n";} else { $firstflag = 0;} print_page($prevstud, $currstud - 1,$currsubj,$#fullsubjary,$pagecount); $pagecount++; } print TEX "\n\\parbox{152mm}{\\vspace{13mm}\\underline{\\hspace{63mm}}"; print TEX "\\hfill\\underline{\\hspace{63mm}}\n\n"; print TEX "{\\small ". $lex{Teacher}. "}\\hfill{\\small ". $lex{Principal}. "}}\n"; print TEX "\\end{document}\n"; close TEX; # alter for tcgi functioning if (getcwd() =~ tcgi) { $downloaddir = $tchdownloaddir; $webdownloaddir = $tchwebdownloaddir; } system("$pdflatex $filename > pdflog$$.txt"); system("mv $shortname.pdf $downloaddir"); system("mv pdflog$$.txt $downloaddir"); system("rm -f $shortname.*"); print "

\n"; print "$lex{'View/Download'} $title

\n"; print "[ $lex{'Report Card'} | \n"; print "$lex{'View Log File'} ]\n"; if ( $missingflag ) { print "

$lex{Note}: "; print "$lex{Missing} $lex{'Short Subject Descriptions'}
\n"; print " Full length subject descriptions are being used. This will
\n"; print "look somewhat ugly, but does indicate the subject.

\n"; } print "
\n"; #---------------- sub showStartPage { #---------------- print "
\n"; print "\n"; print "\n"; print "\n"; # Paper Size print "\n"; print "\n"; print "
$lex{'Select by'}\n"; print "\n"; print "
$lex{'Paper Size'}\n"; print "
\n"; print "
\n"; print "\n"; exit; } #--------------- sub print_header { #--------------- # passed starting and ending values(indexes) for subject, pagenum my ($startsubj, $endsubj, $pagenum) = @_; print TEX "\\begin{tabular}{p{49mm}"; for (my $i = $startsubj; $i <= $endsubj; $i++){ $subjref = $fullsubjary[$i]; for (1..$#$subjref) { print TEX "p{6.15mm}";} } # Print section for attendance and promotion text. print TEX "p{7mm}l"; # Note Left Alignment here. print TEX "}\n\\parbox[b]{47mm}{\\raggedright{\\bf\\large $schoolname}\\\\ $currdate\\hfill\\\\ $lex{Page}:~$pagenum $lex{Term}:~$g_TermDisplay{$g_DefaultTrack}{$term}\\\\ "; if ( $group eq 'grade' ){ print TEX $lex{Grade}. ": $group_value } &\n"; } else { print TEX $lex{Homeroom}. ": $group_value } &\n"; } $count = 0; for ($i = $startsubj; $i <= $endsubj; $i++){ $subjref = $fullsubjary[$i]; if ($i != $startsubj){print TEX "&";} print TEX "\\begin{rotate}{90}{\\small $$subjref[1]}\\end{rotate}"; for (2..$#$subjref) { print TEX "&\\begin{rotate}{90}{\\small $$subjref[$_]}\\end{rotate}"; } } print TEX "&\\rule{0mm}{2mm}\\begin{sideways}{\\small\\bf Attend }\\end{sideways}"; print TEX "&\\parbox[b]{50mm} {\\raggedright\\small P=Complete~Promotion, R=Repeating~Years~Work, SP=Social~Promotion, MA=Modified/Alternate~Program}"; print TEX "\\\\\n\\end{tabular}\n\n"; # Now print header section WITH dividers print TEX "\\begin{tabular}{p{45mm}|"; # foreach $subjref (@fullsubjary){ for ( my $i = $startsubj; $i <= $endsubj; $i++ ) { $subjref = $fullsubjary[$i]; for ( 1 .. $#$subjref ) { print TEX "p{6mm}|";} } # Print section for attendance and promotion text. print TEX "p{12mm}|p{25mm}|"; print TEX "}\\hline\n"; } #-------------- sub print_page { #-------------- # print a single page when passed start, end values for students # as well as subjects. (ie. defining a block) my ($startstud, $endstud, $startsubj, $endsubj,$pagenum) = @_; # print "Page $pagenum Stud: $startstud - $endstud \n"; # print "Sub: $startsubj - $endsubj
\n"; print_header( $startsubj, $endsubj, $pagenum ); my $sth3 = $dbh->prepare("select endrptperiod from subject where subjsec = ?"); my $studcount = 1; # foreach $studref (@$studary){ for (my $j = $startstud; $j <= $endstud; $j++){ $studref = @$studary[$j]; my $lastname = $$studref[1]; my $firstname = $$studref[2]; my $studnum = $$studref[0]; my $gr = $$studref[3]; # grade; needed if homeroom group for ppd. # Find $active value (ie. currently enrolled ) my $sth = $dbh->prepare("select studid from student where studnum = ?"); $sth->execute( $studnum ); if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;} my $active = $sth->fetchall_arrayref; # calc attendance values for this student my $dayspresent = calcAttendance($studnum, $schoolstart, $schoolend, $g_ppd{$gr},$active); # several values from admin.conf config file. $dayspresent = format_number($dayspresent, 2, 2); print TEX "$lastname, $firstname "; # Setup for reading subject table calcavg value. my $sth2 = $dbh->prepare("select calcavg from subject where subjsec = ?"); # Loop through each subject for this student and print eval results. for ( my $i = $startsubj; $i <= $endsubj; $i++ ) { $subjref = $fullsubjary[$i]; # Get his/her evaluation for this subject in this term my $subjsec = $$subjref[0]; my $testavg; # Get the calcavg value (N or Y); $sth2->execute( $subjsec ); if ( $DBI::errstr ){ print $DBI::errstr; die $DBI::errstr; } my $calcavg = $sth2->fetchrow; if ( $calcavg eq $lex{Y} ) { # average all terms to find values... # ~~ Hack to get the subject for all kids... my ($subject,$section) = split /-/,$subjsec; # ~~~ Serious year end hacking here... June/04. my $locobjcount = $#$subjref; # Number of objectives. #print " SUB: $subjsec OBJ: $locobjcount \n"; my $sth1 = $dbh->prepare("select $r_MarkField from eval where studnum = ? and subjcode $sql{like} '$subject%'"); #~~instead of $subjsec $sth1->execute( $studnum ); if ($DBI::errstr) {print $DBI::errstr; die $DBI::errstr; } my ($evalcount, $evaltotal); while (my ($evalrec ) = $sth1->fetchrow ) { if ($evalrec =~ m/\d/){ # if a digit... $evaltotal += $evalrec; $evalcount++; } } if ($evalcount){ # We have some tests. $testavg = $evaltotal / $evalcount; $testavg = format_number( $testavg, 0,0); } else { $testavg = ' '; } } else { # We just find the endreporting period for this # subject and get that term's value from eval table; # Get End Reporting period for final mark $sth3->execute( $subjsec ); if ($DBI::errstr ) { print $DBI::errstr; die $DBI::errstr; } my $endrptperiod = $sth3->fetchrow; my $sth1 = $dbh->prepare("select $r_MarkField from eval where studnum = ? and term = ? and subjcode = ?"); $sth1->execute( $studnum, $endrptperiod, $subjsec ); if ($DBI::errstr) {print $DBI::errstr; die $DBI::errstr; } $testavg = $sth1->fetchrow; } # Note not really a 'test average' if a final mark only. print TEX "&\\hfil{\\small $testavg}\\hfil"; } print TEX "&\\hfil $dayspresent \\hfil& "; # End of line (with space) print TEX "\\\\\\hline\n"; if (not ($studcount % 3)){ print TEX "\\hline\n";} # put in spacers. $studcount++; } # End of Student For print TEX "\\end{tabular}\n\n"; } # End of print_page function #--------------- sub calcTermDays { #--------------- # this calculates the number of schooldays in a date range # taking school holidays into account. ($startdate, $enddate) = @_; # It desires it in yyyymmdd format... $startdate =~ s/-//g; # strip out hyphens. $enddate =~ s/-//g; $end = new Date::Business(DATE=>$enddate); $start = new Date::Business(DATE=>$startdate); $schooldays = $end->diffb($start,'prev','next'); $schooldays++; # We now have the number of school days in current term # excluding holidays/pd days. # Find number of days school not in session this period (holidays) my $sth = $dbh->prepare("select id, date, dayfraction from dates where to_days(date) >= to_days('$startdate') and to_days(date) <= to_days('$enddate')"); $sth->execute; if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr; } my $holidays; while ( my ($id, $date, $dayfraction) = $sth->fetchrow ) { if ( not $dayfraction ) { print "

$lex{Error}: $date $lex{Missing} $lex{Value}

\n"; $dayfraction = 1; } $holidays += $dayfraction; } # Note: may be a decimal, may need rounding. my $termdays = format_number($schooldays - $holidays, 2, 2); return $termdays; } #----------------- sub calcAttendance { #----------------- my ($studnum, $startdate, $enddate, $periodsperday,$active) = @_; my @enrolblocks = findEnrollmentBlocks($studnum, $schoolstart, $currsdate, $dbh); my $absent = 0; my $daysEnrolled = 0; my $late = 0; foreach my $block (@enrolblocks){ my $start = $block->{start}; my $end = $block->{end}; #print "ST: $start END: $end "; my $blocklength = calcTermDays($start,$end); #print "BlockLen: $blocklength
\n"; $daysEnrolled += $blocklength; #print "STUD: $studnum ST: $start END: $end\n"; my $sth = $dbh->prepare("select * from attend where studentid='$studnum' and to_days(absdate) >= to_days('$start') and to_days(absdate) <= to_days('$end') order by absdate,period"); $sth->execute; if ($DBI::errstr) { print $DBI::errstr; die $DBI::errstr;} while (@absence = $sth->fetchrow){ if ($absence[3] =~ /$absentString/) { $absent++; } #if ($absence[3] =~ /$lateString/) { $late++; } } #print "ABS: $absent
\n"; } if (not $periodsperday) { print "PPD: $periodsperday not defined for $studnum
\n"; } $absent = $absent/$periodsperday; #convert periods into days my $present = $daysEnrolled - $absent; return $present; }