You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
869 lines
31 KiB
869 lines
31 KiB
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle 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 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* local functions and constants for module attendance
|
|
*
|
|
* @package mod_attendance
|
|
* @copyright 2011 Artem Andreev <andreev.artem@gmail.com>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
require_once($CFG->libdir . '/gradelib.php');
|
|
require_once(dirname(__FILE__).'/renderhelpers.php');
|
|
|
|
define('ATT_VIEW_DAYS', 1);
|
|
define('ATT_VIEW_WEEKS', 2);
|
|
define('ATT_VIEW_MONTHS', 3);
|
|
define('ATT_VIEW_ALLPAST', 4);
|
|
define('ATT_VIEW_ALL', 5);
|
|
define('ATT_VIEW_NOTPRESENT', 6);
|
|
define('ATT_VIEW_SUMMARY', 7);
|
|
|
|
define('ATT_SORT_DEFAULT', 0);
|
|
define('ATT_SORT_LASTNAME', 1);
|
|
define('ATT_SORT_FIRSTNAME', 2);
|
|
|
|
define('ATTENDANCE_AUTOMARK_DISABLED', 0);
|
|
define('ATTENDANCE_AUTOMARK_ALL', 1);
|
|
define('ATTENDANCE_AUTOMARK_CLOSE', 2);
|
|
|
|
/**
|
|
* Get statuses,
|
|
*
|
|
* @param int $attid
|
|
* @param bool $onlyvisible
|
|
* @param int $statusset
|
|
* @return array
|
|
*/
|
|
function attendance_get_statuses($attid, $onlyvisible=true, $statusset = -1) {
|
|
global $DB;
|
|
|
|
// Set selector.
|
|
$params = array('aid' => $attid);
|
|
$setsql = '';
|
|
if ($statusset >= 0) {
|
|
$params['statusset'] = $statusset;
|
|
$setsql = ' AND setnumber = :statusset ';
|
|
}
|
|
|
|
if ($onlyvisible) {
|
|
$statuses = $DB->get_records_select('attendance_statuses', "attendanceid = :aid AND visible = 1 AND deleted = 0 $setsql",
|
|
$params, 'setnumber ASC, grade DESC');
|
|
} else {
|
|
$statuses = $DB->get_records_select('attendance_statuses', "attendanceid = :aid AND deleted = 0 $setsql",
|
|
$params, 'setnumber ASC, grade DESC');
|
|
}
|
|
|
|
return $statuses;
|
|
}
|
|
|
|
/**
|
|
* Get the name of the status set.
|
|
*
|
|
* @param int $attid
|
|
* @param int $statusset
|
|
* @param bool $includevalues
|
|
* @return string
|
|
*/
|
|
function attendance_get_setname($attid, $statusset, $includevalues = true) {
|
|
$statusname = get_string('statusset', 'mod_attendance', $statusset + 1);
|
|
if ($includevalues) {
|
|
$statuses = attendance_get_statuses($attid, true, $statusset);
|
|
$statusesout = array();
|
|
foreach ($statuses as $status) {
|
|
$statusesout[] = $status->acronym;
|
|
}
|
|
if ($statusesout) {
|
|
if (count($statusesout) > 6) {
|
|
$statusesout = array_slice($statusesout, 0, 6);
|
|
$statusesout[] = '&helip;';
|
|
}
|
|
$statusesout = implode(' ', $statusesout);
|
|
$statusname .= ' ('.$statusesout.')';
|
|
}
|
|
}
|
|
|
|
return $statusname;
|
|
}
|
|
|
|
/**
|
|
* Get users courses and the relevant attendances.
|
|
*
|
|
* @param int $userid
|
|
* @return array
|
|
*/
|
|
function attendance_get_user_courses_attendances($userid) {
|
|
global $DB;
|
|
|
|
$usercourses = enrol_get_users_courses($userid);
|
|
|
|
list($usql, $uparams) = $DB->get_in_or_equal(array_keys($usercourses), SQL_PARAMS_NAMED, 'cid0');
|
|
|
|
$sql = "SELECT att.id as attid, att.course as courseid, course.fullname as coursefullname,
|
|
course.startdate as coursestartdate, att.name as attname, att.grade as attgrade
|
|
FROM {attendance} att
|
|
JOIN {course} course
|
|
ON att.course = course.id
|
|
WHERE att.course $usql
|
|
ORDER BY coursefullname ASC, attname ASC";
|
|
|
|
$params = array_merge($uparams, array('uid' => $userid));
|
|
|
|
return $DB->get_records_sql($sql, $params);
|
|
}
|
|
|
|
/**
|
|
* Used to calculate a fraction based on the part and total values
|
|
*
|
|
* @param float $part - part of the total value
|
|
* @param float $total - total value.
|
|
* @return float the calculated fraction.
|
|
*/
|
|
function attendance_calc_fraction($part, $total) {
|
|
if ($total == 0) {
|
|
return 0;
|
|
} else {
|
|
return $part / $total;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check to see if statusid in use to help prevent deletion etc.
|
|
*
|
|
* @param integer $statusid
|
|
*/
|
|
function attendance_has_logs_for_status($statusid) {
|
|
global $DB;
|
|
return $DB->record_exists('attendance_log', array('statusid' => $statusid));
|
|
}
|
|
|
|
/**
|
|
* Helper function to add sessiondate_selector to add/update forms.
|
|
*
|
|
* @param MoodleQuickForm $mform
|
|
*/
|
|
function attendance_form_sessiondate_selector (MoodleQuickForm $mform) {
|
|
|
|
$mform->addElement('date_selector', 'sessiondate', get_string('sessiondate', 'attendance'));
|
|
|
|
for ($i = 0; $i <= 23; $i++) {
|
|
$hours[$i] = sprintf("%02d", $i);
|
|
}
|
|
for ($i = 0; $i < 60; $i += 5) {
|
|
$minutes[$i] = sprintf("%02d", $i);
|
|
}
|
|
|
|
$sesendtime = array();
|
|
$sesendtime[] =& $mform->createElement('static', 'from', '', get_string('from', 'attendance'));
|
|
$sesendtime[] =& $mform->createElement('select', 'starthour', get_string('hour', 'form'), $hours, false, true);
|
|
$sesendtime[] =& $mform->createElement('select', 'startminute', get_string('minute', 'form'), $minutes, false, true);
|
|
$sesendtime[] =& $mform->createElement('static', 'to', '', get_string('to', 'attendance'));
|
|
$sesendtime[] =& $mform->createElement('select', 'endhour', get_string('hour', 'form'), $hours, false, true);
|
|
$sesendtime[] =& $mform->createElement('select', 'endminute', get_string('minute', 'form'), $minutes, false, true);
|
|
$mform->addGroup($sesendtime, 'sestime', get_string('time', 'attendance'), array(' '), true);
|
|
}
|
|
|
|
/**
|
|
* Count the number of status sets that exist for this instance.
|
|
*
|
|
* @param int $attendanceid
|
|
* @return int
|
|
*/
|
|
function attendance_get_max_statusset($attendanceid) {
|
|
global $DB;
|
|
|
|
$max = $DB->get_field_sql('SELECT MAX(setnumber) FROM {attendance_statuses} WHERE attendanceid = ? AND deleted = 0',
|
|
array($attendanceid));
|
|
if ($max) {
|
|
return $max;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the maxpoints for each statusset
|
|
*
|
|
* @param array $statuses
|
|
* @return array
|
|
*/
|
|
function attendance_get_statusset_maxpoints($statuses) {
|
|
$statussetmaxpoints = array();
|
|
foreach ($statuses as $st) {
|
|
if (!isset($statussetmaxpoints[$st->setnumber])) {
|
|
$statussetmaxpoints[$st->setnumber] = $st->grade;
|
|
}
|
|
}
|
|
return $statussetmaxpoints;
|
|
}
|
|
|
|
/**
|
|
* Update user grades
|
|
*
|
|
* @param mod_attendance_structure|stdClass $attendance
|
|
* @param array $userids
|
|
*/
|
|
function attendance_update_users_grade($attendance, $userids=array()) {
|
|
global $DB;
|
|
|
|
if (empty($attendance->grade)) {
|
|
return false;
|
|
}
|
|
|
|
list($course, $cm) = get_course_and_cm_from_instance($attendance->id, 'attendance');
|
|
|
|
$summary = new mod_attendance_summary($attendance->id, $userids);
|
|
|
|
if (empty($userids)) {
|
|
$context = context_module::instance($cm->id);
|
|
$userids = array_keys(get_enrolled_users($context, 'mod/attendance:canbelisted', 0, 'u.id'));
|
|
}
|
|
|
|
if ($attendance->grade < 0) {
|
|
$dbparams = array('id' => -($attendance->grade));
|
|
$scale = $DB->get_record('scale', $dbparams);
|
|
$scalearray = explode(',', $scale->scale);
|
|
$attendancegrade = count($scalearray);
|
|
} else {
|
|
$attendancegrade = $attendance->grade;
|
|
}
|
|
|
|
$grades = array();
|
|
foreach ($userids as $userid) {
|
|
$grades[$userid] = new stdClass();
|
|
$grades[$userid]->userid = $userid;
|
|
|
|
if ($summary->has_taken_sessions($userid)) {
|
|
$usersummary = $summary->get_taken_sessions_summary_for($userid);
|
|
$grades[$userid]->rawgrade = $usersummary->takensessionspercentage * $attendancegrade;
|
|
} else {
|
|
$grades[$userid]->rawgrade = null;
|
|
}
|
|
}
|
|
|
|
return grade_update('mod/attendance', $course->id, 'mod', 'attendance', $attendance->id, 0, $grades);
|
|
}
|
|
|
|
/**
|
|
* Add an attendance status variable
|
|
*
|
|
* @param stdClass $status
|
|
* @return bool
|
|
*/
|
|
function attendance_add_status($status) {
|
|
global $DB;
|
|
if (empty($status->context)) {
|
|
$status->context = context_system::instance();
|
|
}
|
|
|
|
if (!empty($status->acronym) && !empty($status->description)) {
|
|
$status->deleted = 0;
|
|
$status->visible = 1;
|
|
$status->setunmarked = 0;
|
|
|
|
$id = $DB->insert_record('attendance_statuses', $status);
|
|
$status->id = $id;
|
|
|
|
$event = \mod_attendance\event\status_added::create(array(
|
|
'objectid' => $status->attendanceid,
|
|
'context' => $status->context,
|
|
'other' => array('acronym' => $status->acronym,
|
|
'description' => $status->description,
|
|
'grade' => $status->grade)));
|
|
if (!empty($status->cm)) {
|
|
$event->add_record_snapshot('course_modules', $status->cm);
|
|
}
|
|
$event->add_record_snapshot('attendance_statuses', $status);
|
|
$event->trigger();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a status variable from an attendance instance
|
|
*
|
|
* @param stdClass $status
|
|
* @param stdClass $context
|
|
* @param stdClass $cm
|
|
*/
|
|
function attendance_remove_status($status, $context = null, $cm = null) {
|
|
global $DB;
|
|
if (empty($context)) {
|
|
$context = context_system::instance();
|
|
}
|
|
$DB->set_field('attendance_statuses', 'deleted', 1, array('id' => $status->id));
|
|
$event = \mod_attendance\event\status_removed::create(array(
|
|
'objectid' => $status->id,
|
|
'context' => $context,
|
|
'other' => array(
|
|
'acronym' => $status->acronym,
|
|
'description' => $status->description
|
|
)));
|
|
if (!empty($cm)) {
|
|
$event->add_record_snapshot('course_modules', $cm);
|
|
}
|
|
$event->add_record_snapshot('attendance_statuses', $status);
|
|
$event->trigger();
|
|
}
|
|
|
|
/**
|
|
* Update status variable for a particular Attendance module instance
|
|
*
|
|
* @param stdClass $status
|
|
* @param string $acronym
|
|
* @param string $description
|
|
* @param int $grade
|
|
* @param bool $visible
|
|
* @param stdClass $context
|
|
* @param stdClass $cm
|
|
* @param int $studentavailability
|
|
* @param bool $setunmarked
|
|
* @return array
|
|
*/
|
|
function attendance_update_status($status, $acronym, $description, $grade, $visible,
|
|
$context = null, $cm = null, $studentavailability = null, $setunmarked = false) {
|
|
global $DB;
|
|
|
|
if (empty($context)) {
|
|
$context = context_system::instance();
|
|
}
|
|
|
|
if (isset($visible)) {
|
|
$status->visible = $visible;
|
|
$updated[] = $visible ? get_string('show') : get_string('hide');
|
|
} else if (empty($acronym) || empty($description)) {
|
|
return array('acronym' => $acronym, 'description' => $description);
|
|
}
|
|
|
|
$updated = array();
|
|
|
|
if ($acronym) {
|
|
$status->acronym = $acronym;
|
|
$updated[] = $acronym;
|
|
}
|
|
if ($description) {
|
|
$status->description = $description;
|
|
$updated[] = $description;
|
|
}
|
|
if (isset($grade)) {
|
|
$status->grade = $grade;
|
|
$updated[] = $grade;
|
|
}
|
|
if (isset($studentavailability)) {
|
|
if (empty($studentavailability)) {
|
|
if ($studentavailability !== '0') {
|
|
$studentavailability = null;
|
|
}
|
|
}
|
|
|
|
$status->studentavailability = $studentavailability;
|
|
$updated[] = $studentavailability;
|
|
}
|
|
if ($setunmarked) {
|
|
$status->setunmarked = 1;
|
|
} else {
|
|
$status->setunmarked = 0;
|
|
}
|
|
$DB->update_record('attendance_statuses', $status);
|
|
|
|
$event = \mod_attendance\event\status_updated::create(array(
|
|
'objectid' => $status->attendanceid,
|
|
'context' => $context,
|
|
'other' => array('acronym' => $acronym, 'description' => $description, 'grade' => $grade,
|
|
'updated' => implode(' ', $updated))));
|
|
if (!empty($cm)) {
|
|
$event->add_record_snapshot('course_modules', $cm);
|
|
}
|
|
$event->add_record_snapshot('attendance_statuses', $status);
|
|
$event->trigger();
|
|
}
|
|
|
|
/**
|
|
* Similar to core random_string function but only lowercase letters.
|
|
* designed to make it relatively easy to provide a simple password in class.
|
|
*
|
|
* @param int $length The length of the string to be created.
|
|
* @return string
|
|
*/
|
|
function attendance_random_string($length=6) {
|
|
$randombytes = random_bytes_emulate($length);
|
|
$pool = 'abcdefghijklmnopqrstuvwxyz';
|
|
$pool .= '0123456789';
|
|
$poollen = strlen($pool);
|
|
$string = '';
|
|
for ($i = 0; $i < $length; $i++) {
|
|
$rand = ord($randombytes[$i]);
|
|
$string .= substr($pool, ($rand % ($poollen)), 1);
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Check to see if this session is open for student marking.
|
|
*
|
|
* @param stdclass $sess the session record from attendance_sessions.
|
|
* @return boolean
|
|
*/
|
|
function attendance_can_student_mark($sess) {
|
|
$canmark = false;
|
|
$attconfig = get_config('attendance');
|
|
if (!empty($attconfig->studentscanmark) && !empty($sess->studentscanmark)) {
|
|
if (empty($attconfig->studentscanmarksessiontime)) {
|
|
$canmark = true;
|
|
} else {
|
|
$duration = $sess->duration;
|
|
if (empty($duration)) {
|
|
$duration = $attconfig->studentscanmarksessiontimeend * 60;
|
|
}
|
|
if ($sess->sessdate < time() && time() < ($sess->sessdate + $duration)) {
|
|
$canmark = true;
|
|
}
|
|
}
|
|
}
|
|
return $canmark;
|
|
}
|
|
|
|
/**
|
|
* Generate worksheet for Attendance export
|
|
*
|
|
* @param stdclass $data The data for the report
|
|
* @param string $filename The name of the file
|
|
* @param string $format excel|ods
|
|
*
|
|
*/
|
|
function attendance_exporttotableed($data, $filename, $format) {
|
|
global $CFG;
|
|
|
|
if ($format === 'excel') {
|
|
require_once("$CFG->libdir/excellib.class.php");
|
|
$filename .= ".xls";
|
|
$workbook = new MoodleExcelWorkbook("-");
|
|
} else {
|
|
require_once("$CFG->libdir/odslib.class.php");
|
|
$filename .= ".ods";
|
|
$workbook = new MoodleODSWorkbook("-");
|
|
}
|
|
// Sending HTTP headers.
|
|
$workbook->send($filename);
|
|
// Creating the first worksheet.
|
|
$myxls = $workbook->add_worksheet('Attendances');
|
|
// Format types.
|
|
$formatbc = $workbook->add_format();
|
|
$formatbc->set_bold(1);
|
|
|
|
$myxls->write(0, 0, get_string('course'), $formatbc);
|
|
$myxls->write(0, 1, $data->course);
|
|
$myxls->write(1, 0, get_string('group'), $formatbc);
|
|
$myxls->write(1, 1, $data->group);
|
|
|
|
$i = 3;
|
|
$j = 0;
|
|
foreach ($data->tabhead as $cell) {
|
|
// Merge cells if the heading would be empty (remarks column).
|
|
if (empty($cell)) {
|
|
$myxls->merge_cells($i, $j - 1, $i, $j);
|
|
} else {
|
|
$myxls->write($i, $j, $cell, $formatbc);
|
|
}
|
|
$j++;
|
|
}
|
|
$i++;
|
|
$j = 0;
|
|
foreach ($data->table as $row) {
|
|
foreach ($row as $cell) {
|
|
$myxls->write($i, $j++, $cell);
|
|
}
|
|
$i++;
|
|
$j = 0;
|
|
}
|
|
$workbook->close();
|
|
}
|
|
|
|
/**
|
|
* Generate csv for Attendance export
|
|
*
|
|
* @param stdclass $data The data for the report
|
|
* @param string $filename The name of the file
|
|
*
|
|
*/
|
|
function attendance_exporttocsv($data, $filename) {
|
|
$filename .= ".txt";
|
|
|
|
header("Content-Type: application/download\n");
|
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
|
header("Expires: 0");
|
|
header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
|
|
header("Pragma: public");
|
|
|
|
echo get_string('course')."\t".$data->course."\n";
|
|
echo get_string('group')."\t".$data->group."\n\n";
|
|
|
|
echo implode("\t", $data->tabhead)."\n";
|
|
foreach ($data->table as $row) {
|
|
echo implode("\t", $row)."\n";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get session data for form.
|
|
* @param stdClass $formdata moodleform - attendance form.
|
|
* @param mod_attendance_structure $att - used to get attendance level subnet.
|
|
* @return array.
|
|
*/
|
|
function attendance_construct_sessions_data_for_add($formdata, mod_attendance_structure $att) {
|
|
global $CFG;
|
|
|
|
$sesstarttime = $formdata->sestime['starthour'] * HOURSECS + $formdata->sestime['startminute'] * MINSECS;
|
|
$sesendtime = $formdata->sestime['endhour'] * HOURSECS + $formdata->sestime['endminute'] * MINSECS;
|
|
$sessiondate = $formdata->sessiondate + $sesstarttime;
|
|
$duration = $sesendtime - $sesstarttime;
|
|
$now = time();
|
|
|
|
if (empty(get_config('attendance', 'studentscanmark'))) {
|
|
$formdata->studentscanmark = 0;
|
|
}
|
|
|
|
$sessions = array();
|
|
if (isset($formdata->addmultiply)) {
|
|
$startdate = $sessiondate;
|
|
$enddate = $formdata->sessionenddate + DAYSECS; // Because enddate in 0:0am.
|
|
|
|
if ($enddate < $startdate) {
|
|
return null;
|
|
}
|
|
|
|
// Getting first day of week.
|
|
$sdate = $startdate;
|
|
$dinfo = usergetdate($sdate);
|
|
if ($CFG->calendar_startwday === '0') { // Week start from sunday.
|
|
$startweek = $startdate - $dinfo['wday'] * DAYSECS; // Call new variable.
|
|
} else {
|
|
$wday = $dinfo['wday'] === 0 ? 7 : $dinfo['wday'];
|
|
$startweek = $startdate - ($wday - 1) * DAYSECS;
|
|
}
|
|
|
|
$wdaydesc = array(0 => 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
|
|
|
|
while ($sdate < $enddate) {
|
|
if ($sdate < $startweek + WEEKSECS) {
|
|
$dinfo = usergetdate($sdate);
|
|
if (isset($formdata->sdays) && array_key_exists($wdaydesc[$dinfo['wday']], $formdata->sdays)) {
|
|
$sess = new stdClass();
|
|
$sess->sessdate = make_timestamp($dinfo['year'], $dinfo['mon'], $dinfo['mday'],
|
|
$formdata->sestime['starthour'], $formdata->sestime['startminute']);
|
|
$sess->duration = $duration;
|
|
$sess->descriptionitemid = $formdata->sdescription['itemid'];
|
|
$sess->description = $formdata->sdescription['text'];
|
|
$sess->descriptionformat = $formdata->sdescription['format'];
|
|
$sess->timemodified = $now;
|
|
if (isset($formdata->studentscanmark)) { // Students will be able to mark their own attendance.
|
|
$sess->studentscanmark = 1;
|
|
if (!empty($formdata->usedefaultsubnet)) {
|
|
$sess->subnet = $att->subnet;
|
|
} else {
|
|
$sess->subnet = $formdata->subnet;
|
|
}
|
|
$sess->automark = $formdata->automark;
|
|
if (isset($formdata->autoassignstatus)) {
|
|
$sess->autoassignstatus = 1;
|
|
}
|
|
$sess->automarkcompleted = 0;
|
|
if (!empty($formdata->randompassword)) {
|
|
$sess->studentpassword = attendance_random_string();
|
|
} else {
|
|
$sess->studentpassword = $formdata->studentpassword;
|
|
}
|
|
} else {
|
|
$sess->studentpassword = '';
|
|
$sess->subnet = '';
|
|
$sess->automark = 0;
|
|
$sess->automarkcompleted = 0;
|
|
}
|
|
$sess->statusset = $formdata->statusset;
|
|
|
|
attendance_fill_groupid($formdata, $sessions, $sess);
|
|
}
|
|
$sdate += DAYSECS;
|
|
} else {
|
|
$startweek += WEEKSECS * $formdata->period;
|
|
$sdate = $startweek;
|
|
}
|
|
}
|
|
} else {
|
|
$sess = new stdClass();
|
|
$sess->sessdate = $sessiondate;
|
|
$sess->duration = $duration;
|
|
$sess->descriptionitemid = $formdata->sdescription['itemid'];
|
|
$sess->description = $formdata->sdescription['text'];
|
|
$sess->descriptionformat = $formdata->sdescription['format'];
|
|
$sess->timemodified = $now;
|
|
$sess->studentscanmark = 0;
|
|
$sess->autoassignstatus = 0;
|
|
$sess->subnet = '';
|
|
$sess->studentpassword = '';
|
|
$sess->automark = 0;
|
|
$sess->automarkcompleted = 0;
|
|
$sess->absenteereport = 1;
|
|
|
|
if (isset($formdata->studentscanmark) && !empty($formdata->studentscanmark)) {
|
|
// Students will be able to mark their own attendance.
|
|
$sess->studentscanmark = 1;
|
|
if (isset($formdata->autoassignstatus) && !empty($formdata->autoassignstatus)) {
|
|
$sess->autoassignstatus = 1;
|
|
}
|
|
if (!empty($formdata->randompassword)) {
|
|
$sess->studentpassword = attendance_random_string();
|
|
} else if (!empty($formdata->studentpassword)) {
|
|
$sess->studentpassword = $formdata->studentpassword;
|
|
}
|
|
if (!empty($formdata->usedefaultsubnet)) {
|
|
$sess->subnet = $att->subnet;
|
|
} else {
|
|
$sess->subnet = $formdata->subnet;
|
|
}
|
|
|
|
if (!empty($formdata->automark)) {
|
|
$sess->automark = $formdata->automark;
|
|
}
|
|
}
|
|
$sess->statusset = $formdata->statusset;
|
|
|
|
attendance_fill_groupid($formdata, $sessions, $sess);
|
|
}
|
|
|
|
return $sessions;
|
|
}
|
|
|
|
/**
|
|
* Helper function for attendance_construct_sessions_data_for_add().
|
|
*
|
|
* @param stdClass $formdata
|
|
* @param stdClass $sessions
|
|
* @param stdClass $sess
|
|
*/
|
|
function attendance_fill_groupid($formdata, &$sessions, $sess) {
|
|
if ($formdata->sessiontype == mod_attendance_structure::SESSION_COMMON) {
|
|
$sess = clone $sess;
|
|
$sess->groupid = 0;
|
|
$sessions[] = $sess;
|
|
} else {
|
|
foreach ($formdata->groups as $groupid) {
|
|
$sess = clone $sess;
|
|
$sess->groupid = $groupid;
|
|
$sessions[] = $sess;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a summary of points for the courses selected.
|
|
*
|
|
* @param array $courseids optional list of courses to return
|
|
* @param string $orderby - optional order by param
|
|
* @return stdClass
|
|
*/
|
|
function attendance_course_users_points($courseids = array(), $orderby = '') {
|
|
global $DB;
|
|
|
|
$where = '';
|
|
$params = array();
|
|
$where .= ' AND ats.sessdate < :enddate ';
|
|
$params['enddate'] = time();
|
|
|
|
$joingroup = 'LEFT JOIN {groups_members} gm ON (gm.userid = atl.studentid AND gm.groupid = ats.groupid)';
|
|
$where .= ' AND (ats.groupid = 0 or gm.id is NOT NULL)';
|
|
|
|
if (!empty($courseids)) {
|
|
list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
|
|
$where .= ' AND c.id ' . $insql;
|
|
$params = array_merge($params, $inparams);
|
|
}
|
|
|
|
$sql = "SELECT courseid, coursename, sum(points) / sum(maxpoints) as percentage FROM (
|
|
SELECT a.id, a.course as courseid, c.fullname as coursename, atl.studentid AS userid, COUNT(DISTINCT ats.id) AS numtakensessions,
|
|
SUM(stg.grade) AS points, SUM(stm.maxgrade) AS maxpoints
|
|
FROM {attendance_sessions} ats
|
|
JOIN {attendance} a ON a.id = ats.attendanceid
|
|
JOIN {course} c ON c.id = a.course
|
|
JOIN {attendance_log} atl ON (atl.sessionid = ats.id)
|
|
JOIN {attendance_statuses} stg ON (stg.id = atl.statusid AND stg.deleted = 0 AND stg.visible = 1)
|
|
JOIN (SELECT attendanceid, setnumber, MAX(grade) AS maxgrade
|
|
FROM {attendance_statuses}
|
|
WHERE deleted = 0
|
|
AND visible = 1
|
|
GROUP BY attendanceid, setnumber) stm
|
|
ON (stm.setnumber = ats.statusset AND stm.attendanceid = ats.attendanceid)
|
|
{$joingroup}
|
|
WHERE ats.sessdate >= c.startdate
|
|
AND ats.lasttaken != 0
|
|
{$where}
|
|
GROUP BY a.id, a.course, c.fullname, atl.studentid
|
|
) p GROUP by courseid, coursename {$orderby}";
|
|
|
|
return $DB->get_records_sql($sql, $params);
|
|
}
|
|
|
|
/**
|
|
* Generates a list of users flagged absent.
|
|
*
|
|
* @param array $courseids optional list of courses to return
|
|
* @param string $orderby how to order results.
|
|
* @param bool $allfornotify get notification list for scheduled task.
|
|
* @return stdClass
|
|
*/
|
|
function attendance_get_users_to_notify($courseids = array(), $orderby = '', $allfornotify = false) {
|
|
global $DB;
|
|
|
|
$joingroup = 'LEFT JOIN {groups_members} gm ON (gm.userid = atl.studentid AND gm.groupid = ats.groupid)';
|
|
$where = ' AND (ats.groupid = 0 or gm.id is NOT NULL)';
|
|
$having = '';
|
|
$params = array();
|
|
|
|
if (!empty($courseids)) {
|
|
list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
|
|
$where .= ' AND c.id ' . $insql;
|
|
$params = array_merge($params, $inparams);
|
|
}
|
|
if ($allfornotify) {
|
|
// Exclude warnings that have already sent the max num.
|
|
$having .= ' AND n.maxwarn > COUNT(DISTINCT ns.id) ';
|
|
}
|
|
|
|
$unames = get_all_user_name_fields(true);
|
|
$unames2 = get_all_user_name_fields(true, 'u');
|
|
|
|
$idfield = $DB->sql_concat('cm.id', 'atl.studentid', 'n.id');
|
|
$sql = "SELECT {$idfield} as uniqueid, a.id as aid, {$unames2}, a.name as aname, cm.id as cmid, c.id as courseid,
|
|
c.fullname as coursename, atl.studentid AS userid, n.id as notifyid, n.warningpercent, n.emailsubject,
|
|
n.emailcontent, n.emailcontentformat, n.emailuser, n.thirdpartyemails, n.warnafter, n.maxwarn,
|
|
COUNT(DISTINCT ats.id) AS numtakensessions, SUM(stg.grade) AS points, SUM(stm.maxgrade) AS maxpoints,
|
|
COUNT(DISTINCT ns.id) as nscount, MAX(ns.timesent) as timesent,
|
|
SUM(stg.grade) / SUM(stm.maxgrade) AS percent
|
|
FROM {attendance_sessions} ats
|
|
JOIN {attendance} a ON a.id = ats.attendanceid
|
|
JOIN {course_modules} cm ON cm.instance = a.id
|
|
JOIN {course} c on c.id = cm.course
|
|
JOIN {modules} md ON md.id = cm.module AND md.name = 'attendance'
|
|
JOIN {attendance_log} atl ON (atl.sessionid = ats.id)
|
|
JOIN {user} u ON (u.id = atl.studentid)
|
|
JOIN {attendance_statuses} stg ON (stg.id = atl.statusid AND stg.deleted = 0 AND stg.visible = 1)
|
|
JOIN {attendance_warning} n ON n.idnumber = a.id
|
|
LEFT JOIN {attendance_warning_done} ns ON ns.notifyid = n.id AND ns.userid = atl.studentid
|
|
JOIN (SELECT attendanceid, setnumber, MAX(grade) AS maxgrade
|
|
FROM {attendance_statuses}
|
|
WHERE deleted = 0
|
|
AND visible = 1
|
|
GROUP BY attendanceid, setnumber) stm
|
|
ON (stm.setnumber = ats.statusset AND stm.attendanceid = ats.attendanceid)
|
|
{$joingroup}
|
|
WHERE ats.absenteereport = 1 {$where}
|
|
GROUP BY uniqueid, a.id, a.name, a.course, c.fullname, atl.studentid, n.id, n.warningpercent,
|
|
n.emailsubject, n.emailcontent, n.emailcontentformat, n.warnafter, n.maxwarn,
|
|
n.emailuser, n.thirdpartyemails, cm.id, c.id, {$unames2}, ns.userid
|
|
HAVING n.warnafter <= COUNT(DISTINCT ats.id) AND n.warningpercent > ((SUM(stg.grade) / SUM(stm.maxgrade)) * 100)
|
|
{$having}
|
|
{$orderby}";
|
|
|
|
if (!$allfornotify) {
|
|
$idfield = $DB->sql_concat('cmid', 'userid');
|
|
// Only show one record per attendance for teacher reports.
|
|
$sql = "SELECT DISTINCT {$idfield} as id, {$unames}, aid, cmid, courseid, aname, coursename, userid,
|
|
numtakensessions, percent, MAX(timesent) as timesent
|
|
FROM ({$sql}) as m
|
|
GROUP BY id, aid, cmid, courseid, aname, userid, numtakensessions,
|
|
percent, coursename, {$unames} {$orderby}";
|
|
}
|
|
|
|
return $DB->get_records_sql($sql, $params);
|
|
|
|
}
|
|
|
|
/**
|
|
* Template variables into place in supplied email content.
|
|
*
|
|
* @param object $record db record of details
|
|
* @return array - the content of the fields after templating.
|
|
*/
|
|
function attendance_template_variables($record) {
|
|
$templatevars = array(
|
|
'/%coursename%/' => $record->coursename,
|
|
'/%courseid%/' => $record->courseid,
|
|
'/%userfirstname%/' => $record->firstname,
|
|
'/%userlastname%/' => $record->lastname,
|
|
'/%userid%/' => $record->userid,
|
|
'/%warningpercent%/' => $record->warningpercent,
|
|
'/%attendancename%/' => $record->aname,
|
|
'/%cmid%/' => $record->cmid,
|
|
'/%numtakensessions%/' => $record->numtakensessions,
|
|
'/%points%/' => $record->points,
|
|
'/%maxpoints%/' => $record->maxpoints,
|
|
'/%percent%/' => $record->percent,
|
|
);
|
|
$extrauserfields = get_all_user_name_fields();
|
|
foreach ($extrauserfields as $extra) {
|
|
$templatevars['/%'.$extra.'%/'] = $record->$extra;
|
|
}
|
|
$patterns = array_keys($templatevars); // The placeholders which are to be replaced.
|
|
$replacements = array_values($templatevars); // The values which are to be templated in for the placeholders.
|
|
// Array to describe which fields in reengagement object should have a template replacement.
|
|
$replacementfields = array('emailsubject', 'emailcontent');
|
|
|
|
// Replace %variable% with relevant value everywhere it occurs in reengagement->field.
|
|
foreach ($replacementfields as $field) {
|
|
$record->$field = preg_replace($patterns, $replacements, $record->$field);
|
|
}
|
|
return $record;
|
|
}
|
|
|
|
/**
|
|
* Find highest available status for a user.
|
|
*
|
|
* @param mod_attendance_structure $att attendance structure
|
|
* @param stdclass $attforsession attendance_session record.
|
|
* @return bool/int
|
|
*/
|
|
function attendance_session_get_highest_status(mod_attendance_structure $att, $attforsession) {
|
|
// Find the status to set here.
|
|
$statuses = $att->get_statuses();
|
|
$highestavailablegrade = 0;
|
|
$highestavailablestatus = new stdClass();
|
|
foreach ($statuses as $status) {
|
|
if ($status->studentavailability === '0') {
|
|
// This status is never available to students.
|
|
continue;
|
|
}
|
|
if (!empty($status->studentavailability)) {
|
|
$toolateforstatus = (($attforsession->sessdate + ($status->studentavailability * 60)) < time());
|
|
if ($toolateforstatus) {
|
|
continue;
|
|
}
|
|
}
|
|
// This status is available to the student.
|
|
if ($status->grade > $highestavailablegrade) {
|
|
// This is the most favourable grade so far; save it.
|
|
$highestavailablegrade = $status->grade;
|
|
$highestavailablestatus = $status;
|
|
}
|
|
}
|
|
if (empty($highestavailablestatus)) {
|
|
return false;
|
|
}
|
|
return $highestavailablestatus->id;
|
|
}
|