diff --git a/classes/page_with_filter_controls.php b/classes/page_with_filter_controls.php index 9617e8f..cadc9f1 100644 --- a/classes/page_with_filter_controls.php +++ b/classes/page_with_filter_controls.php @@ -124,6 +124,10 @@ class mod_attendance_page_with_filter_controls { $this->startdate = 0; $this->enddate = 0; break; + case ATT_VIEW_SUMMARY: + $this->startdate = 1; + $this->enddate = 1; + break; } } @@ -221,4 +225,4 @@ class mod_attendance_page_with_filter_controls { public function set_current_sesstype($sesstype) { $this->sesstype = $sesstype; } -} \ No newline at end of file +} diff --git a/classes/structure.php b/classes/structure.php index 67d67ff..4acc3a7 100644 --- a/classes/structure.php +++ b/classes/structure.php @@ -61,10 +61,6 @@ class mod_attendance_structure { // Array by sessionid. private $sessioninfo = array(); - // Arrays by userid. - private $usertakensesscount = array(); - private $userstatusesstat = array(); - /** * Initializes the attendance API instance using the data from DB * @@ -233,6 +229,7 @@ class mod_attendance_structure { 'edate' => $this->pageparams->enddate, 'cgroup' => $this->pageparams->get_current_sesstype()); $sessions = $DB->get_records_select('attendance_sessions', $where, $params, 'sessdate asc'); + $statussetmaxpoints = attendance_get_statusset_maxpoints($this->get_statuses(true, true)); foreach ($sessions as $sess) { if (empty($sess->description)) { $sess->description = get_string('nodescription', 'attendance'); @@ -240,6 +237,7 @@ class mod_attendance_structure { $sess->description = file_rewrite_pluginfile_urls($sess->description, 'pluginfile.php', $this->context->id, 'mod_attendance', 'session', $sess->id); } + $sess->maxpoints = $statussetmaxpoints[$sess->statusset]; } return $sessions; @@ -746,138 +744,8 @@ class mod_attendance_structure { return $DB->get_records('attendance_log', array('sessionid' => $sessionid), '', 'studentid,statusid,remarks,id'); } - public function get_user_stat($userid) { - $ret = array(); - $ret['completed'] = $this->get_user_taken_sessions_count($userid); - $ret['statuses'] = $this->get_user_statuses_stat($userid); - - return $ret; - } - - public function get_user_taken_sessions_count($userid) { - if (!array_key_exists($userid, $this->usertakensesscount)) { - if (!empty($this->pageparams->startdate) && !empty($this->pageparams->enddate)) { - $this->usertakensesscount[$userid] = attendance_get_user_taken_sessions_count($this->id, $this->course->startdate, - $userid, $this->cm, $this->pageparams->startdate, $this->pageparams->enddate); - } else { - $this->usertakensesscount[$userid] = attendance_get_user_taken_sessions_count($this->id, $this->course->startdate, - $userid, $this->cm); - } - } - return $this->usertakensesscount[$userid]; - } - - /** - * - * @param type $userid - * @param type $filters - An array things to filter by. For now only enddate is valid. - * @return type - */ - public function get_user_statuses_stat($userid, array $filters = null) { - global $DB; - $params = array( - 'aid' => $this->id, - 'cstartdate' => $this->course->startdate, - 'uid' => $userid); - - $processedfilters = array(); - - // We test for any valid filters sent. - if (isset($filters['enddate'])) { - $processedfilters[] = 'ats.sessdate <= :enddate'; - $params['enddate'] = $filters['enddate']; - } - - // Make the filter array into a SQL string. - if (!empty($processedfilters)) { - $processedfilters = ' AND '.implode(' AND ', $processedfilters); - } else { - $processedfilters = ''; - } - - $period = ''; - if (!empty($this->pageparams->startdate) && !empty($this->pageparams->enddate)) { - $period = ' AND ats.sessdate >= :sdate AND ats.sessdate < :edate '; - $params['sdate'] = $this->pageparams->startdate; - $params['edate'] = $this->pageparams->enddate; - } - - if ($this->get_group_mode()) { - $qry = "SELECT al.statusid, count(al.statusid) AS stcnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats ON al.sessionid = ats.id - LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid AND - (ats.groupid = 0 or gm.id is NOT NULL)".$period.$processedfilters." - GROUP BY al.statusid"; - } else { - $qry = "SELECT al.statusid, count(al.statusid) AS stcnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats - ON al.sessionid = ats.id - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid".$period.$processedfilters." - GROUP BY al.statusid"; - } - - // We do not want to cache, or use a cached version of the results when a filter is set. - if ($filters !== null) { - return $DB->get_records_sql($qry, $params); - } else if (!array_key_exists($userid, $this->userstatusesstat)) { - // Not filtered so if we do not already have them do the query. - $this->userstatusesstat[$userid] = $DB->get_records_sql($qry, $params); - } - - // Return the cached stats. - return $this->userstatusesstat[$userid]; - } - - /** - * - * @param type $userid - * @param type $filters - An array things to filter by. For now only enddate is valid. - * @return type - */ - public function get_user_grade($userid, array $filters = null) { - return attendance_get_user_grade($this->get_user_statuses_stat($userid, $filters), $this->get_statuses(true, true)); - } - - // For getting sessions count implemented simplest method - taken sessions. - // It can have error if users don't have attendance info for some sessions. - // In the future we can implement another methods: - // * all sessions between user start enrolment date and now; - // * all sessions between user start and end enrolment date. - // While implementing those methods we need recalculate grades of all users - // on session adding. - public function get_user_max_grade($userid) { - return attendance_get_user_max_grade($this->get_user_taken_sessions_count($userid), $this->get_statuses(true, true)); - } - public function update_users_grade($userids) { - global $DB; - $grades = array(); - - if ($this->grade < 0) { - $dbparams = array('id' => -($this->grade)); - $this->scale = $DB->get_record('scale', $dbparams); - $scalearray = explode(',', $this->scale->scale); - $attendancegrade = count($scalearray); - } else { - $attendancegrade = $this->grade; - } - - foreach ($userids as $userid) { - $grades[$userid] = new stdClass(); - $grades[$userid]->userid = $userid; - $grades[$userid]->rawgrade = attendance_calc_user_grade_fraction($this->get_user_grade($userid), - $this->get_user_max_grade($userid)) * $attendancegrade; - } - - return grade_update('mod/attendance', $this->course->id, 'mod', 'attendance', - $this->id, 0, $grades); + attendance_update_users_grade($this, $userids); } public function get_user_filtered_sessions_log($userid) { @@ -950,7 +818,7 @@ class mod_attendance_structure { WHERE $where AND (ats.groupid = 0 or gm.id is NOT NULL) ORDER BY ats.sessdate ASC"; } else { - $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, + $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, ats.statusset, al.statusid, al.remarks, ats.studentscanmark FROM {attendance_sessions} ats RIGHT JOIN {attendance_log} al @@ -981,7 +849,7 @@ class mod_attendance_structure { $where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate AND ats.groupid $gsql"; } - $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, + $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, ats.statusset, al.statusid, al.remarks, ats.studentscanmark FROM {attendance_sessions} ats LEFT JOIN {attendance_log} al diff --git a/classes/summary.php b/classes/summary.php new file mode 100644 index 0000000..9b5cf2b --- /dev/null +++ b/classes/summary.php @@ -0,0 +1,268 @@ +. + +/** + * Class that computes summary of users points + * + * @package mod_attendance + * @copyright 2016 Antonio Carlos Mariani http://antonio.c.mariani@gmail.com + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once($CFG->dirroot . '/mod/attendance/locallib.php'); + +class mod_attendance_summary { + + /** @var int attendance instance identifier */ + private $attendanceid; + + /** @var stdclass course course data*/ + private $course; + + /** @var int groupmode*/ + private $groupmode; + + /** @var array userspoints (userid, numtakensessions, points, maxpoints) */ + private $userspoints; + + /** @var array pointsbygroup (groupid, numsessions, maxpoints) */ + private $maxpointsbygroupsessions; + + /** + * Initializes the class + * + * @param int attendance instance identifier + * @param array userids user instances identifier + * @param int $startdate Attendance sessions startdate + * @param int $enddate Attendance sessions enddate + */ + public function __construct($attendanceid, $userids=array(), $startdate = '', $enddate = '') { + $this->attendanceid = $attendanceid; + + $this->compute_users_points($userids, $startdate, $enddate); + } + + /** + * Returns true if the user has some session with points + * + * @param int userid User instance id + * + * @return boolean + */ + public function has_taken_sessions($userid) { + return isset($this->userspoints[$userid]); + } + + /** + * Returns true if the corresponding attendance instance is currently configure to work with grades (points) + * + * @return boolean + */ + public function with_groups() { + return $this->groupmode > 0; + } + + /** + * Returns the groupmode of the corresponding attendance instance + * + * @return int + */ + public function get_groupmode() { + return $this->groupmode; + } + + /** + * Returns the percentages of each user related to the taken sessions + * + * @return array + */ + public function get_user_taken_sessions_percentages() { + $percentages = array(); + + foreach ($this->userspoints as $userid => $userpoints) { + $percentages[$userid] = attendance_calc_fraction($userpoints->points, $userpoints->maxpoints); + } + + return $percentages; + } + + /** + * Returns a summary of the points assigned to the user related to the taken sessions + * + * @param int userid User instance id + * + * @return array + */ + public function get_taken_sessions_summary_for($userid) { + $usersummary = new stdClass(); + if ($this->has_taken_sessions($userid)) { + $usersummary->numtakensessions = $this->userspoints[$userid]->numtakensessions; + $usersummary->takensessionspoints = $this->userspoints[$userid]->points; + $usersummary->takensessionsmaxpoints = $this->userspoints[$userid]->maxpoints; + } else { + $usersummary->numtakensessions = 0; + $usersummary->takensessionspoints = 0; + $usersummary->takensessionsmaxpoints = 0; + } + $usersummary->takensessionspercentage = attendance_calc_fraction($usersummary->takensessionspoints, + $usersummary->takensessionsmaxpoints); + + return $usersummary; + } + + /** + * Returns a summary of the points assigned to the user, both related to taken sessions and related to all sessions + * + * @param int userid User instance id + * + * @return array + */ + public function get_all_sessions_summary_for($userid) { + $usersummary = $this->get_taken_sessions_summary_for($userid); + + if (!isset($this->maxpointsbygroupsessions)) { + $this->compute_maxpoints_by_group_session(); + } + + $usersummary->numallsessions = $this->maxpointsbygroupsessions[0]->numsessions; + $usersummary->allsessionsmaxpoints = $this->maxpointsbygroupsessions[0]->maxpoints; + + if ($this->with_groups()) { + $groupids = array_keys(groups_get_all_groups($this->course->id, $userid)); + foreach ($groupids as $gid) { + if (isset($this->maxpointsbygroupsessions[$gid])) { + $usersummary->numallsessions += $this->maxpointsbygroupsessions[$gid]->numsessions; + $usersummary->allsessionsmaxpoints += $this->maxpointsbygroupsessions[$gid]->maxpoints; + } + } + } + $usersummary->allsessionspercentage = attendance_calc_fraction($usersummary->takensessionspoints, + $usersummary->allsessionsmaxpoints); + + $deltapoints = $usersummary->allsessionsmaxpoints - $usersummary->takensessionsmaxpoints; + $usersummary->maxpossiblepoints = $usersummary->takensessionspoints + $deltapoints; + $usersummary->maxpossiblepercentage = attendance_calc_fraction($usersummary->maxpossiblepoints, + $usersummary->allsessionsmaxpoints); + + return $usersummary; + } + + /** + * Computes the summary of points for the users that have some taken session + * + * @param array userids user instances identifier + * @param int $startdate Attendance sessions startdate + * @param int $enddate Attendance sessions enddate + * @return (userid, numtakensessions, points, maxpoints) + */ + private function compute_users_points($userids=array(), $startdate = '', $enddate = '') { + global $DB; + + list($this->course, $cm) = get_course_and_cm_from_instance($this->attendanceid, 'attendance'); + $this->groupmode = $cm->effectivegroupmode; + + $params = array( + 'attid' => $this->attendanceid, + 'attid2' => $this->attendanceid, + 'cstartdate' => $this->course->startdate, + ); + + $where = ''; + if (!empty($userids)) { + list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); + $where .= ' AND atl.studentid ' . $insql; + $params = array_merge($params, $inparams); + } + if (!empty($startdate)) { + $where .= ' AND ats.sessdate >= :startdate'; + $params['startdate'] = $startdate; + } + if (!empty($enddate)) { + $where .= ' AND ats.sessdate < :enddate '; + $params['enddate'] = $enddate; + } + + $joingroup = ''; + if ($this->with_groups()) { + $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)'; + } else { + $where .= ' AND ats.groupid = 0'; + } + + $sql = " SELECT 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_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 setnumber, MAX(grade) AS maxgrade + FROM {attendance_statuses} + WHERE attendanceid = :attid2 + AND deleted = 0 + AND visible = 1 + GROUP BY setnumber) stm + ON (stm.setnumber = ats.statusset) + {$joingroup} + WHERE ats.attendanceid = :attid + AND ats.sessdate >= :cstartdate + AND ats.lasttakenby != 0 + {$where} + GROUP BY atl.studentid"; + $this->userspoints = $DB->get_records_sql($sql, $params); + } + + /** + * Computes and store the maximum points possible for each group session + * + * @return null + */ + private function compute_maxpoints_by_group_session() { + global $DB; + + $params = array( + 'attid' => $this->attendanceid, + 'attid2' => $this->attendanceid, + 'cstartdate' => $this->course->startdate, + ); + + $where = ''; + if (!$this->with_groups()) { + $where = 'AND sess.groupid = 0'; + } + + $sql = "SELECT sess.groupid, COUNT(*) AS numsessions, SUM(stamax.maxgrade) AS maxpoints + FROM {attendance_sessions} sess + JOIN (SELECT setnumber, MAX(grade) AS maxgrade + FROM {attendance_statuses} + WHERE attendanceid = :attid2 + AND deleted = 0 + AND visible = 1 + GROUP BY setnumber) stamax + ON (stamax.setnumber = sess.statusset) + WHERE sess.attendanceid = :attid + AND sess.sessdate >= :cstartdate + {$where} + GROUP BY sess.groupid"; + $this->maxpointsbygroupsessions = $DB->get_records_sql($sql, $params); + + if (!isset($this->maxpointsbygroupsessions[0])) { + $gpoints = new stdClass(); + $gpoints->numsessions = 0; + $gpoints->maxpoints = 0; + $this->maxpointsbygroupsessions[0] = $gpoints; + } + } +} diff --git a/export.php b/export.php index e270487..ead107a 100644 --- a/export.php +++ b/export.php @@ -123,10 +123,9 @@ if ($formdata = $mform->get_data()) { } else { print_error('sessionsnotfound', 'attendance', $att->url_manage()); } - if ($reportdata->gradable) { - $data->tabhead[] = get_string('grade'); - $data->tabhead[] = get_string('percentage', 'attendance'); - } + $data->tabhead[] = get_string('takensessions', 'attendance'); + $data->tabhead[] = get_string('points', 'attendance'); + $data->tabhead[] = get_string('percentage', 'attendance'); $i = 0; $data->table = array(); @@ -158,16 +157,13 @@ if ($formdata = $mform->get_data()) { } $cellsgenerator = new user_sessions_cells_text_generator($reportdata, $user); $data->table[$i] = array_merge($data->table[$i], $cellsgenerator->get_cells(isset($formdata->includeremarks))); - if ($reportdata->gradable) { - $data->table[$i][] = format_float($reportdata->grades[$user->id]).' / '. - format_float($reportdata->maxgrades[$user->id]); - if ($reportdata->maxgrades[$user->id]) { - $percent = $reportdata->grades[$user->id] * 100.0 / $reportdata->maxgrades[$user->id]; - } else { - $percent = 0.0; - } - $data->table[$i][] = $percent; - } + + $usersummary = $reportdata->summary->get_taken_sessions_summary_for($user->id); + $data->table[$i][] = $usersummary->numtakensessions; + $data->table[$i][] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' . + format_float($usersummary->takensessionsmaxpoints, 1, true, true); + $data->table[$i][] = format_float($usersummary->takensessionspercentage * 100); + $i++; } diff --git a/lang/en/attendance.php b/lang/en/attendance.php index 8c1f312..18f6889 100644 --- a/lang/en/attendance.php +++ b/lang/en/attendance.php @@ -133,6 +133,8 @@ $string['indetail'] = 'In detail...'; $string['invalidsessionenddate'] = 'This date can not be earlier than the session date'; $string['invalidaction'] = 'You must select an action'; $string['jumpto'] = 'Jump to'; +$string['maxpossiblepoints'] = 'Maximum possible points'; +$string['maxpossiblepercentage'] = 'Maximum possible percentage'; $string['mergeuser'] = 'Merge user'; $string['modulename'] = 'Attendance'; $string['modulename_help'] = 'The attendance activity module enables a teacher to take attendance during class and students to view their own attendance record. @@ -165,6 +167,8 @@ $string['olddate'] = 'Old date'; $string['onlyselectedusers'] = 'Export specific users'; $string['participant'] = 'Participant'; $string['percentage'] = 'Percentage'; +$string['percentagesessionscompleted'] = 'Percentage over taked sessions'; +$string['percentageallsessions'] = 'Percentage over all sessions'; $string['pluginname'] = 'Attendance'; $string['pluginadministration'] = 'Attendance administration'; $string['remark'] = 'Remark for: {$a}'; @@ -221,7 +225,8 @@ $string['sessiondays'] = 'Session Days'; $string['sessiondeleted'] = 'Session successfully deleted'; $string['sessionexist'] = 'Session not added (already exists)!'; $string['sessions'] = 'Sessions'; -$string['sessionscompleted'] = 'Sessions completed'; +$string['sessionscompleted'] = 'Taked sessions'; +$string['sessionstotal'] = 'Total number of sessions'; $string['sessionsids'] = 'IDs of sessions: '; $string['sessiongenerated'] = 'One session was successfully generated'; $string['sessionsgenerated'] = '{$a} sessions were successfully generated'; @@ -255,7 +260,9 @@ $string['strftimedmyw'] = '%d.%m.%y (%a)'; $string['strftimehm'] = '%H:%M'; // Line added to allow display of time. $string['strftimeshortdate'] = '%d.%m.%Y'; $string['studentid'] = 'Student ID'; +$string['summary'] = 'Summary'; $string['takeattendance'] = 'Take attendance'; +$string['takensessions'] = 'Taken sessions'; $string['tempaddform'] = 'Add temporary user'; $string['tempexists'] = 'There is already a temporary user with this email address'; $string['tempusers'] = 'Temporary users'; @@ -301,6 +308,8 @@ $string['submitattendance'] = 'Submit attendance'; $string['attendancenotset'] = 'You must set your attendance'; $string['export'] = 'Export'; $string['points'] = 'Points'; +$string['pointssessionscompleted'] = 'Points over taked sessions'; +$string['pointsallsessions'] = 'Points over all sessions'; $string['unknowngroup'] = 'Unknown group'; $string['notmember'] = 'not member'; diff --git a/lib.php b/lib.php index eeb9d03..dad7d2f 100644 --- a/lib.php +++ b/lib.php @@ -250,7 +250,7 @@ function attendance_user_complete($course, $user, $mod, $attendance) { require_once($CFG->libdir.'/gradelib.php'); if (has_capability('mod/attendance:canbelisted', $mod->context, $user->id)) { - echo construct_full_user_stat_html_table($attendance, $course, $user, $mod); + echo construct_full_user_stat_html_table($attendance, $user); } } @@ -276,7 +276,7 @@ function attendance_grade_item_update($attendance, $grades=null) { if (!isset($attendance->courseid)) { $attendance->courseid = $attendance->course; } - if (! $course = $DB->get_record('course', array('id' => $attendance->course))) { + if (!$DB->get_record('course', array('id' => $attendance->course))) { error("Course is misconfigured"); } @@ -284,7 +284,6 @@ function attendance_grade_item_update($attendance, $grades=null) { $params = array('itemname' => $attendance->name, 'idnumber' => $attendance->cmidnumber); } else { // MDL-14303. - $cm = get_coursemodule_from_instance('attendance', $attendance->id); $params = array('itemname' => $attendance->name/*, 'idnumber'=>$attendance->id*/); } diff --git a/locallib.php b/locallib.php index 9cd860e..22a5c1e 100644 --- a/locallib.php +++ b/locallib.php @@ -33,6 +33,7 @@ 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_LASTNAME', 1); define('ATT_SORT_FIRSTNAME', 2); @@ -88,86 +89,6 @@ function attendance_get_setname($attid, $statusset, $includevalues = true) { return $statusname; } -function attendance_get_user_taken_sessions_count($attid, $coursestartdate, $userid, $coursemodule, $startdate = '', $enddate = '') { - global $DB, $COURSE; - $groupmode = groups_get_activity_groupmode($coursemodule, $COURSE); - if (!empty($groupmode)) { - $qry = "SELECT count(*) as cnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats ON al.sessionid = ats.id - LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid AND - (ats.groupid = 0 or gm.id is NOT NULL)"; - } else { - $qry = "SELECT count(*) as cnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats - ON al.sessionid = ats.id - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid"; - } - $params = array( - 'aid' => $attid, - 'cstartdate' => $coursestartdate, - 'uid' => $userid); - - if (!empty($startdate) && !empty($enddate)) { - $qry .= ' AND sessdate >= :sdate AND sessdate < :edate '; - $params['sdate'] = $startdate; - $params['edate'] = $enddate; - } - - return $DB->count_records_sql($qry, $params); -} - -function attendance_get_user_statuses_stat($attid, $coursestartdate, $userid, $coursemodule) { - global $DB, $COURSE; - $groupmode = groups_get_activity_groupmode($coursemodule, $COURSE); - if (!empty($groupmode)) { - $qry = "SELECT al.statusid, count(al.statusid) AS stcnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats ON al.sessionid = ats.id - LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid AND - (ats.groupid = 0 or gm.id is NOT NULL) - GROUP BY al.statusid"; - } else { - $qry = "SELECT al.statusid, count(al.statusid) AS stcnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats - ON al.sessionid = ats.id - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid - GROUP BY al.statusid"; - } - $params = array( - 'aid' => $attid, - 'cstartdate' => $coursestartdate, - 'uid' => $userid); - - return $DB->get_records_sql($qry, $params); -} - -function attendance_get_user_grade($userstatusesstat, $statuses) { - $sum = 0; - foreach ($userstatusesstat as $stat) { - $sum += $stat->stcnt * $statuses[$stat->statusid]->grade; - } - - return $sum; -} - -function attendance_get_user_max_grade($sesscount, $statuses) { - reset($statuses); - return current($statuses)->grade * $sesscount; -} - function attendance_get_user_courses_attendances($userid) { global $DB; @@ -189,71 +110,18 @@ function attendance_get_user_courses_attendances($userid) { } /** - * Used to caclulate usergrade based on rawgrade and max grade. + * Used to calculate a fraction based on the part and total values * - * @param float $grade - raw grade for user - * @param float $maxgrade - maxgrade for this session. - * @return float the calculated grade. + * @param float $part - part of the total value + * @param float $total - total value. + * @return float the calculated fraction. */ -function attendance_calc_user_grade_fraction($grade, $maxgrade) { - if ($maxgrade == 0) { +function attendance_calc_fraction($part, $total) { + if ($total == 0) { return 0; } else { - return $grade / $maxgrade; - } -} - -/** - * Update all user grades - used when settings have changed. - * - * @param mod_attendance_structure $attendance - Full attendance class. - * @param stdclass $coursemodule - full coursemodule record - * @return float the calculated grade. - */ -function attendance_update_all_users_grades(mod_attendance_structure $attendance, $coursemodule) { - global $DB; - $grades = array(); - $course = $attendance->course; - - $userids = array_keys(get_enrolled_users($attendance->context, 'mod/attendance:canbelisted', 0, 'u.id')); - $attgrades = grade_get_grades($course->id, 'mod', 'attendance', $attendance->id, $userids); - - $usergrades = []; - if (!empty($attgrades->items[0]) and !empty($attgrades->items[0]->grades)) { - $usergrades = $attgrades->items[0]->grades; - } - $statuses = attendance_get_statuses($attendance->id); - if ($attendance->grade < 0) { - $dbparams = array('id' => -($attendance->grade)); - $scale = $DB->get_record('scale', $dbparams); - $scalearray = explode(',', $scale->scale); - $gradebookmaxgrade = count($scalearray); - } else { - $gradebookmaxgrade = $attendance->grade; - } - foreach ($usergrades as $userid => $existinggrade) { - if (is_null($existinggrade->grade)) { - // Don't update grades where one doesn't exist yet. - continue; - } - $grade = new stdClass; - $grade->userid = $userid; - $userstatusesstat = attendance_get_user_statuses_stat($attendance->id, $course->startdate, $userid, $coursemodule); - $usertakensesscount = attendance_get_user_taken_sessions_count($attendance->id, $course->startdate, $userid, $coursemodule); - $usergrade = attendance_get_user_grade($userstatusesstat, $statuses); - $usermaxgrade = attendance_get_user_max_grade($usertakensesscount, $statuses); - $grade->rawgrade = attendance_calc_user_grade_fraction($usergrade, $usermaxgrade) * $gradebookmaxgrade; - $grades[$userid] = $grade; - } - - if (!empty($grades)) { - $result = grade_update('mod/attendance', $course->id, 'mod', 'attendance', - $attendance->id, 0, $grades); - } else { - $result = true; + return $part / $total; } - - return $result; } /** @@ -308,3 +176,66 @@ function attendance_get_max_statusset($attendanceid) { } 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 mixed 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); +} diff --git a/preferences.php b/preferences.php index 061912a..194dd54 100644 --- a/preferences.php +++ b/preferences.php @@ -122,9 +122,7 @@ switch ($att->pageparams->action) { $status = $statuses[$id]; $errors[$id] = $att->update_status($status, $acronym[$id], $description[$id], $grade[$id], null); } - if ($att->grade > 0) { - attendance_update_all_users_grades($att, $cm); - } + attendance_update_users_grade($att); break; } diff --git a/renderables.php b/renderables.php index 0c7f764..1131573 100644 --- a/renderables.php +++ b/renderables.php @@ -128,7 +128,7 @@ class attendance_filter_controls implements renderable { private $urlpath; private $urlparams; - private $att; + public $att; public function __construct(mod_attendance_structure $att, $report = false) { global $PAGE; @@ -138,7 +138,7 @@ class attendance_filter_controls implements renderable { $this->cm = $att->cm; // This is a report control only if $reports is true and the attendance block can be graded. - $this->reportcontrol = $report && ($att->grade > 0); + $this->reportcontrol = $report; $this->curdate = $att->pageparams->curdate; @@ -336,17 +336,9 @@ class attendance_user_data implements renderable { public $pageparams; - public $stat; - public $statuses; - public $gradable; - - public $grade; - - public $maxgrade; - - public $decimalpoints; + public $summary; public $filtercontrols; @@ -360,26 +352,15 @@ class attendance_user_data implements renderable { private $urlparams; public function __construct(mod_attendance_structure $att, $userid) { - global $CFG; - $this->user = $att->get_user($userid); $this->pageparams = $att->pageparams; - if (!$this->decimalpoints = grade_get_setting($att->course->id, 'decimalpoints')) { - $this->decimalpoints = $CFG->grade_decimalpoints; - } - if ($this->pageparams->mode == mod_attendance_view_page_params::MODE_THIS_COURSE) { $this->statuses = $att->get_statuses(true, true); - $this->stat = $att->get_user_stat($userid); - - $this->gradable = $att->grade > 0; - if ($this->gradable) { - $this->grade = $att->get_user_grade($userid); - $this->maxgrade = $att->get_user_max_grade($userid); - } + $this->summary = new mod_attendance_summary($att->id, array($userid), $att->pageparams->startdate, + $att->pageparams->enddate); $this->filtercontrols = new attendance_filter_controls($att); @@ -389,40 +370,15 @@ class attendance_user_data implements renderable { } else { $this->coursesatts = attendance_get_user_courses_attendances($userid); $this->statuses = array(); - $this->stat = array(); - $this->gradable = array(); - $this->grade = array(); - $this->maxgrade = array(); + $this->summary = array(); foreach ($this->coursesatts as $atid => $ca) { // Check to make sure the user can view this cm. if (!get_fast_modinfo($ca->courseid)->instances['attendance'][$ca->attid]->uservisible) { unset($this->courseatts[$atid]); continue; } - $statuses = attendance_get_statuses($ca->attid); - $usertakensessionscount = attendance_get_user_taken_sessions_count($ca->attid, $ca->coursestartdate, $userid, $att->cm); - $userstatusesstat = attendance_get_user_statuses_stat($ca->attid, $ca->coursestartdate, $userid, $att->cm); - - $this->statuses[$ca->attid] = $statuses; - - $this->stat[$ca->attid]['completed'] = $usertakensessionscount; - $this->stat[$ca->attid]['statuses'] = $userstatusesstat; - - $this->gradable[$ca->attid] = $ca->attgrade > 0; - - if ($this->gradable[$ca->attid]) { - $this->grade[$ca->attid] = attendance_get_user_grade($userstatusesstat, $statuses); - // For getting sessions count implemented simplest method - taken sessions. - // It can have error if users don't have attendance info for some sessions. - // In the future we can implement another methods: - // * all sessions between user start enrolment date and now; - // * all sessions between user start and end enrolment date. - $this->maxgrade[$ca->attid] = attendance_get_user_max_grade($usertakensessionscount, $statuses); - } else { - // For more comfortable and universal work with arrays. - $this->grade[$ca->attid] = null; - $this->maxgrade[$ca->attid] = null; - } + $this->statuses[$ca->attid] = attendance_get_statuses($ca->attid); + $this->summary[$ca->attid] = new mod_attendance_summary($ca->attid, array($userid)); } } $this->urlpath = $att->url_view()->out_omit_querystring(); @@ -449,25 +405,15 @@ class attendance_report_data implements renderable { // Includes disablrd/deleted statuses. public $allstatuses; - public $gradable; - - public $decimalpoints; - public $usersgroups = array(); public $sessionslog = array(); - public $usersstats = array(); - - public $grades = array(); - - public $maxgrades = array(); + public $summary = array(); public $att; public function __construct(mod_attendance_structure $att) { - global $CFG; - $currenttime = time(); if ($att->pageparams->view == ATT_VIEW_NOTPRESENT) { $att->pageparams->enddate = $currenttime; @@ -492,32 +438,21 @@ class attendance_report_data implements renderable { $this->statuses = $att->get_statuses(true, true); $this->allstatuses = $att->get_statuses(false, true); - $this->gradable = $att->grade > 0; - - if (!$this->decimalpoints = grade_get_setting($att->course->id, 'decimalpoints')) { - $this->decimalpoints = $CFG->grade_decimalpoints; + if ($att->pageparams->view == ATT_VIEW_SUMMARY) { + $this->summary = new mod_attendance_summary($att->id); + } else { + $this->summary = new mod_attendance_summary($att->id, array_keys($this->users), + $att->pageparams->startdate, $att->pageparams->enddate); } - $maxgrade = attendance_get_user_max_grade(count($this->sessions), $this->statuses); - foreach ($this->users as $key => $user) { - $grade = 0; - if ($this->gradable) { - $grade = $att->get_user_grade($user->id, array('enddate' => $currenttime)); - $totalgrade = $att->get_user_grade($user->id); - } - - if ($att->pageparams->view != ATT_VIEW_NOTPRESENT || $grade < $maxgrade) { + $usersummary = $this->summary->get_taken_sessions_summary_for($user->id); + if ($att->pageparams->view != ATT_VIEW_NOTPRESENT || + $usersummary->takensessionspoints < $usersummary->takensessionsmaxpoints || + $usersummary->takensessionsmaxpoints == 0) { $this->usersgroups[$user->id] = groups_get_all_groups($att->course->id, $user->id); $this->sessionslog[$user->id] = $att->get_user_filtered_sessions_log($user->id); - - $this->usersstats[$user->id] = $att->get_user_statuses_stat($user->id); - - if ($this->gradable) { - $this->grades[$user->id] = $totalgrade; - $this->maxgrades[$user->id] = $att->get_user_max_grade($user->id);; - } } else { unset($this->users[$key]); } diff --git a/renderer.php b/renderer.php index fe86450..e8c7b36 100644 --- a/renderer.php +++ b/renderer.php @@ -176,12 +176,15 @@ class mod_attendance_renderer extends plugin_renderer_base { protected function render_view_controls(attendance_filter_controls $fcontrols) { $views[ATT_VIEW_ALL] = get_string('all', 'attendance'); $views[ATT_VIEW_ALLPAST] = get_string('allpast', 'attendance'); - if ($fcontrols->reportcontrol) { + if ($fcontrols->reportcontrol && $fcontrols->att->grade > 0) { $views[ATT_VIEW_NOTPRESENT] = get_string('lowgrade', 'attendance'); } $views[ATT_VIEW_MONTHS] = get_string('months', 'attendance'); $views[ATT_VIEW_WEEKS] = get_string('weeks', 'attendance'); $views[ATT_VIEW_DAYS] = get_string('days', 'attendance'); + if ($fcontrols->reportcontrol) { + $views[ATT_VIEW_SUMMARY] = get_string('summary', 'attendance'); + } $viewcontrols = ''; foreach ($views as $key => $sview) { if ($key != $fcontrols->pageparams->view) { @@ -299,8 +302,6 @@ class mod_attendance_renderer extends plugin_renderer_base { } protected function render_sess_manage_control(attendance_manage_data $sessdata) { - global $OUTPUT; - $table = new html_table(); $table->attributes['class'] = ' '; $table->width = '100%'; @@ -735,8 +736,8 @@ class mod_attendance_renderer extends plugin_renderer_base { if ($userdata->pageparams->mode == mod_attendance_view_page_params::MODE_THIS_COURSE) { $o .= html_writer::empty_tag('hr'); - $o .= construct_user_data_stat($userdata->stat, $userdata->statuses, - $userdata->gradable, $userdata->grade, $userdata->maxgrade, $userdata->decimalpoints); + $o .= construct_user_data_stat($userdata->summary->get_all_sessions_summary_for($userdata->user->id), + $userdata->pageparams->view); $o .= $this->render_attendance_filter_controls($userdata->filtercontrols); @@ -752,9 +753,12 @@ class mod_attendance_renderer extends plugin_renderer_base { } $o .= html_writer::tag('h4', $ca->attname); - $o .= construct_user_data_stat($userdata->stat[$ca->attid], $userdata->statuses[$ca->attid], - $userdata->gradable[$ca->attid], $userdata->grade[$ca->attid], - $userdata->maxgrade[$ca->attid], $userdata->decimalpoints); + if (isset($userdata->summary[$ca->attid])) { + $usersummary = $userdata->summary[$ca->attid]->get_all_sessions_summary_for($userdata->user->id); + } else { + $usersummary = null; + } + $o .= construct_user_data_stat($usersummary, ATT_VIEW_ALL); } } @@ -771,10 +775,13 @@ class mod_attendance_renderer extends plugin_renderer_base { get_string('time'), get_string('description', 'attendance'), get_string('status', 'attendance'), + get_string('points', 'attendance'), get_string('remarks', 'attendance') ); - $table->align = array('', '', '', 'left', 'left', 'center', 'left', 'center'); - $table->size = array('1px', '1px', '1px', '1px', '*', '1px', '1px', '*'); + $table->align = array('', '', '', 'left', 'left', 'center', 'center', 'center'); + $table->size = array('1px', '1px', '1px', '1px', '*', '*', '1px', '*'); + + $statussetmaxpoints = attendance_get_statusset_maxpoints($userdata->statuses); $i = 0; foreach ($userdata->sessionslog as $sess) { @@ -793,7 +800,10 @@ class mod_attendance_renderer extends plugin_renderer_base { $row->cells[] = $this->construct_time($sess->sessdate, $sess->duration); $row->cells[] = $sess->description; if (isset($sess->statusid)) { - $row->cells[] = $userdata->statuses[$sess->statusid]->description; + $status = $userdata->statuses[$sess->statusid]; + $row->cells[] = $status->description; + $row->cells[] = format_float($status->grade, 1, true, true) . ' / ' . + format_float($statussetmaxpoints[$status->setnumber], 1, true, true); $row->cells[] = $sess->remarks; } else if ($sess->sessdate < $userdata->user->enrolmentstart) { $cell = new html_table_cell(get_string('enrolmentstart', 'attendance', @@ -815,6 +825,7 @@ class mod_attendance_renderer extends plugin_renderer_base { $row->cells[] = $cell; } else { // Student cannot mark their own attendace. $row->cells[] = '?'; + $row->cells[] = '? / ' . format_float($statussetmaxpoints[$sess->statusset], 1, true, true); $row->cells[] = ''; } } @@ -843,6 +854,9 @@ class mod_attendance_renderer extends plugin_renderer_base { $table = new html_table(); $table->attributes['class'] = 'generaltable attwidth'; + if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) { + $table->attributes['class'] .= ' summaryreport'; + } // User picture. $table->head[] = ''; @@ -882,15 +896,36 @@ class mod_attendance_renderer extends plugin_renderer_base { $table->size[] = '1px'; } - foreach ($reportdata->statuses as $status) { - $table->head[] = $status->acronym; + $table->head[] = get_string('takensessions', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '1px'; + + $table->head[] = get_string('points', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '1px'; + + $table->head[] = get_string('percentage', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '1px'; + + if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) { + $table->head[] = get_string('sessionstotal', 'attendance'); $table->align[] = 'center'; $table->size[] = '1px'; - $sessionstats[$status->id] = 0; - } - if ($reportdata->gradable) { - $table->head[] = get_string('grade'); + $table->head[] = get_string('pointsallsessions', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '1px'; + + $table->head[] = get_string('percentageallsessions', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '1px'; + + $table->head[] = get_string('maxpossiblepoints', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '1px'; + + $table->head[] = get_string('maxpossiblepercentage', 'attendance'); $table->align[] = 'center'; $table->size[] = '1px'; } @@ -910,17 +945,25 @@ class mod_attendance_renderer extends plugin_renderer_base { $cellsgenerator = new user_sessions_cells_html_generator($reportdata, $user); $row->cells = array_merge($row->cells, $cellsgenerator->get_cells(true)); - foreach ($reportdata->statuses as $status) { - if (array_key_exists($status->id, $reportdata->usersstats[$user->id])) { - $row->cells[] = $reportdata->usersstats[$user->id][$status->id]->stcnt; - } else { - // No attendance data for this $status => no statistic for this status. - $row->cells[] = 0; - } + if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) { + $usersummary = $reportdata->summary->get_all_sessions_summary_for($user->id); + } else { + $usersummary = $reportdata->summary->get_taken_sessions_summary_for($user->id); } - - if ($reportdata->gradable) { - $row->cells[] = format_float($reportdata->grades[$user->id]).' / '.format_float($reportdata->maxgrades[$user->id]); + $row->cells[] = $usersummary->numtakensessions; + $row->cells[] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' . + format_float($usersummary->takensessionsmaxpoints, 1, true, true); + $row->cells[] = format_float($usersummary->takensessionspercentage * 100) . '%'; + + if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) { + $row->cells[] = $usersummary->numallsessions; + $row->cells[] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' . + format_float($usersummary->allsessionsmaxpoints, 1, true, true); + $row->cells[] = format_float($usersummary->allsessionspercentage * 100) . '%'; + + $row->cells[] = format_float($usersummary->maxpossiblepoints, 1, true, true) . ' / ' . + format_float($usersummary->allsessionsmaxpoints, 1, true, true); + $row->cells[] = format_float($usersummary->maxpossiblepercentage * 100) . '%'; } if ($bulkmessagecapability) { // Create the checkbox for bulk messaging. @@ -936,22 +979,30 @@ class mod_attendance_renderer extends plugin_renderer_base { $statrow->cells[] = ''; $statrow->cells[] = get_string('summary'); foreach ($reportdata->sessions as $sess) { + $sessionstats = array(); + foreach ($reportdata->statuses as $status) { + if ($status->setnumber == $sess->statusset) { + $status->count = 0; + $sessionstats[$status->id] = $status; + } + } + foreach ($reportdata->users as $user) { - foreach ($reportdata->statuses as $status) { - if (!empty($reportdata->sessionslog[$user->id][$sess->id])) { - if ($reportdata->sessionslog[$user->id][$sess->id]->statusid == $status->id) { - $sessionstats[$status->id]++; - } + if (!empty($reportdata->sessionslog[$user->id][$sess->id])) { + $statusid = $reportdata->sessionslog[$user->id][$sess->id]->statusid; + if (isset($sessionstats[$statusid]->count)) { + $sessionstats[$statusid]->count++; } } } $statsoutput = '
'; - foreach ($reportdata->statuses as $status) { - $statsoutput .= "$status->description:".$sessionstats[$status->id]."
"; + foreach ($sessionstats as $status) { + $statsoutput .= "$status->description: {$status->count}
"; } - $statrow->cells[] = $statsoutput; - + $cell = new html_table_cell($statsoutput); + $cell->style = 'white-space:nowrap;'; + $statrow->cells[] = $cell; } $table->data[] = $statrow; @@ -1008,7 +1059,7 @@ class mod_attendance_renderer extends plugin_renderer_base { $table->head = array('#', get_string('acronym', 'attendance'), get_string('description'), - get_string('grade'), + get_string('points', 'attendance'), get_string('action')); $table->align = array('center', 'center', 'center', 'center', 'center', 'center'); diff --git a/renderhelpers.php b/renderhelpers.php index e89dbbb..bf07176 100644 --- a/renderhelpers.php +++ b/renderhelpers.php @@ -49,7 +49,10 @@ class user_sessions_cells_generator { if (array_key_exists($sess->id, $this->reportdata->sessionslog[$this->user->id])) { $statusid = $this->reportdata->sessionslog[$this->user->id][$sess->id]->statusid; if (array_key_exists($statusid, $this->reportdata->statuses)) { - $this->construct_existing_status_cell($this->reportdata->statuses[$statusid]->acronym); + $points = format_float($this->reportdata->statuses[$statusid]->grade, 1, true, true); + $maxpoints = format_float($sess->maxpoints, 1, true, true); + $this->construct_existing_status_cell($this->reportdata->statuses[$statusid]->acronym . + " ({$points}/{$maxpoints})"); } else { $this->construct_hidden_status_cell($this->reportdata->allstatuses[$statusid]->acronym); } @@ -228,65 +231,66 @@ function construct_session_full_date_time($datetime, $duration) { return $sessinfo; } -function construct_user_data_stat($stat, $statuses, $gradable, $grade, $maxgrade, $decimalpoints) { - global $OUTPUT; - +function construct_user_data_stat($usersummary, $view) { $stattable = new html_table(); $stattable->attributes['class'] = 'attlist'; $row = new html_table_row(); - $row->cells[] = get_string('sessionscompleted', 'attendance').':'; - $row->cells[] = $stat['completed']; + $row->attributes['class'] = 'normal'; + $row->cells[] = get_string('sessionscompleted', 'attendance') . ':'; + $row->cells[] = $usersummary->numtakensessions; $stattable->data[] = $row; - foreach ($statuses as $st) { + $row = new html_table_row(); + $row->attributes['class'] = 'normal'; + $row->cells[] = get_string('pointssessionscompleted', 'attendance') . ':'; + $row->cells[] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' . + format_float($usersummary->takensessionsmaxpoints, 1, true, true); + $stattable->data[] = $row; + + $row = new html_table_row(); + $row->attributes['class'] = 'normal'; + $row->cells[] = get_string('percentagesessionscompleted', 'attendance') . ':'; + $row->cells[] = format_float($usersummary->takensessionspercentage * 100) . '%'; + $stattable->data[] = $row; + + if ($view == ATT_VIEW_ALL) { + $row = new html_table_row(); + $row->attributes['class'] = 'highlight'; + $row->cells[] = get_string('sessionstotal', 'attendance') . ':'; + $row->cells[] = $usersummary->numallsessions; + $stattable->data[] = $row; + $row = new html_table_row(); - $row->cells[] = $st->description . ':'; - $row->cells[] = array_key_exists($st->id, $stat['statuses']) ? $stat['statuses'][$st->id]->stcnt : 0; + $row->attributes['class'] = 'highlight'; + $row->cells[] = get_string('pointsallsessions', 'attendance') . ':'; + $row->cells[] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' . + format_float($usersummary->allsessionsmaxpoints, 1, true, true); + $stattable->data[] = $row; + $row = new html_table_row(); + $row->attributes['class'] = 'highlight'; + $row->cells[] = get_string('percentageallsessions', 'attendance') . ':'; + $row->cells[] = format_float($usersummary->allsessionspercentage * 100) . '%'; $stattable->data[] = $row; - } - if ($gradable) { $row = new html_table_row(); - $row->cells[] = get_string('attendancegrade', 'attendance') . - $OUTPUT->help_icon('gradebookexplanation', 'attendance') . ':'; - $row->cells[] = format_float($grade) . ' / ' . format_float($maxgrade); + $row->attributes['class'] = 'normal'; + $row->cells[] = get_string('maxpossiblepoints', 'attendance') . ':'; + $row->cells[] = format_float($usersummary->maxpossiblepoints, 1, true, true) . ' / ' . + format_float($usersummary->allsessionsmaxpoints, 1, true, true); $stattable->data[] = $row; $row = new html_table_row(); - $row->cells[] = get_string('attendancepercent', 'attendance') . ':'; - if ($maxgrade == 0) { - $percent = 0; - } else { - $percent = $grade / $maxgrade * 100; - } - $row->cells[] = format_float(sprintf("%0.{$decimalpoints}f", $percent)); + $row->attributes['class'] = 'normal'; + $row->cells[] = get_string('maxpossiblepercentage', 'attendance') . ':'; + $row->cells[] = format_float($usersummary->maxpossiblepercentage * 100) . '%'; $stattable->data[] = $row; } return html_writer::table($stattable); } -function construct_full_user_stat_html_table($attendance, $course, $user, $coursemodule) { - global $CFG; - $gradeable = $attendance->grade > 0; - $statuses = attendance_get_statuses($attendance->id); - $userstatusesstat = attendance_get_user_statuses_stat($attendance->id, $course->startdate, $user->id, $coursemodule); - $stat['completed'] = attendance_get_user_taken_sessions_count($attendance->id, $course->startdate, $user->id, $coursemodule); - $stat['statuses'] = $userstatusesstat; - if ($gradeable) { - $grade = attendance_get_user_grade($userstatusesstat, $statuses); - $maxgrade = attendance_get_user_max_grade(attendance_get_user_taken_sessions_count($attendance->id, $course->startdate, - $user->id, $coursemodule), $statuses); - if (!$decimalpoints = grade_get_setting($course->id, 'decimalpoints')) { - $decimalpoints = $CFG->grade_decimalpoints; - } - } else { - $grade = 0; - $maxgrade = 0; - $decimalpoints = 0; - } - - return construct_user_data_stat($stat, $statuses, - $gradeable, $grade, $maxgrade, $decimalpoints); +function construct_full_user_stat_html_table($attendance, $user) { + $summary = new mod_attendance_summary($attendance->id, $user->id); + return construct_user_data_stat($summary->get_all_sessions_summary_for($user->id), ATT_VIEW_ALL); } diff --git a/sessions.php b/sessions.php index dc790f8..f879a1a 100644 --- a/sessions.php +++ b/sessions.php @@ -113,9 +113,7 @@ switch ($att->pageparams->action) { if (isset($confirm) && confirm_sesskey()) { $att->delete_sessions(array($sessionid)); - if ($att->grade > 0) { - attendance_update_all_users_grades($att, $cm); - } + attendance_update_users_grade($att); redirect($att->url_manage(), get_string('sessiondeleted', 'attendance')); } @@ -142,9 +140,7 @@ switch ($att->pageparams->action) { $sessionsids = explode('_', $sessionsids); $att->delete_sessions($sessionsids); - if ($att->grade > 0) { - attendance_update_all_users_grades($att, $cm); - } + attendance_update_users_grade($att); redirect($att->url_manage(), get_string('sessiondeleted', 'attendance')); } $sessid = optional_param_array('sessid', '', PARAM_SEQUENCE); diff --git a/styles.css b/styles.css index 4186842..52a860a 100644 --- a/styles.css +++ b/styles.css @@ -17,7 +17,7 @@ } .path-mod-attendance .attfiltercontrols { - margin-bottom: 10px; + margin-bottom: 10px !important; margin-right:auto; margin-left:auto; } @@ -164,4 +164,16 @@ .path-mod-attendance .attendancestatus-A { color: red; -} \ No newline at end of file +} + +.path-mod-attendance .summaryreport .c5 { + background-color: #EAEAEA; +} + +.path-mod-attendance .summaryreport .c6 { + background-color: #EAEAEA; +} + +.path-mod-attendance .summaryreport .c7 { + background-color: #EAEAEA; +} diff --git a/tests/behat/report.feature b/tests/behat/report.feature new file mode 100644 index 0000000..26f41fa --- /dev/null +++ b/tests/behat/report.feature @@ -0,0 +1,240 @@ +@javascript @mod @uon @mod_attendance +Feature: Visiting reports + As a teacher I visit the reports + + Background: + Given the following "courses" exist: + | fullname | shortname | summary | category | + | Course 1 | C101 | Prove the attendance activity works | 0 | + And the following "users" exist: + | username | firstname | lastname | email | idnumber | department | institution | + | student1 | Student | 1 | student1@asd.com | 1234 | computer science | University of Nottingham | + | teacher1 | Teacher | 1 | teacher1@asd.com | 5678 | computer science | University of Nottingham | + And the following "course enrolments" exist: + | user | course | role | + | student1 | C101 | student | + | teacher1 | C101 | editingteacher | + + And I log in as "teacher1" + And I follow "Course 1" + And I turn editing mode on + Then I add a "Attendance" to section "1" + And I press "Save and display" + And I follow "Attendance" + And I follow "Add session" + And I set the following fields to these values: + | id_sestime_starthour | 01 | + | id_sestime_endhour | 02 | + And I click on "id_submitbutton" "button" + + And I log out + + Scenario: Teacher takes attendance + When I log in as "teacher1" + And I follow "Course 1" + And I follow "Attendance" + And I follow "Edit settings" + Then I set the following fields to these values: + | id_grade_modgrade_type | Point | + | id_grade_modgrade_point | 50 | + And I press "Save and display" + + When I follow "Report" + Then "0 / 0" "text" should exist in the "Student 1" "table_row" + And "0.0%" "text" should exist in the "Student 1" "table_row" + + When I follow "Grades" in the user menu + And I follow "Course 1" + And "-" "text" should exist in the "Student 1" "table_row" + + When I follow "Attendance" + Then I click on "Take attendance" "link" in the "01:00 - 02:00" "table_row" + # Late + And I click on "td.c3 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Report" + Then "1 / 2" "text" should exist in the "Student 1" "table_row" + And "50.0%" "text" should exist in the "Student 1" "table_row" + + When I follow "Grades" in the user menu + And I follow "Course 1" + And "25.00" "text" should exist in the "Student 1" "table_row" + + And I log out + + Scenario: Teacher changes the maximum points in the attendance settings + When I log in as "teacher1" + And I follow "Course 1" + And I follow "Attendance" + And I follow "Edit settings" + Then I set the following fields to these values: + | id_grade_modgrade_type | Point | + | id_grade_modgrade_point | 50 | + And I press "Save and display" + + When I follow "Attendance" + Then I click on "Take attendance" "link" in the "01:00 - 02:00" "table_row" + # Excused + And I click on "td.c3 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Attendance" + And I follow "Edit settings" + Then I set the following fields to these values: + | id_grade_modgrade_type | Point | + | id_grade_modgrade_point | 70 | + And I press "Save and display" + + When I follow "Report" + Then "1 / 2" "text" should exist in the "Student 1" "table_row" + And "50.0%" "text" should exist in the "Student 1" "table_row" + + When I follow "Grades" in the user menu + And I follow "Course 1" + Then "35.00" "text" should exist in the "Student 1" "table_row" + + And I log out + + Scenario: Teacher take attendance of group session + Given the following "groups" exist: + | course | name | idnumber | + | C101 | Group1 | Group1 | + And the following "group members" exist: + | group | user | + | Group1 | student1 | + + When I log in as "teacher1" + And I follow "Course 1" + And I follow "Attendance" + And I follow "Edit settings" + And I set the following fields to these values: + | id_grade_modgrade_type | Point | + | id_grade_modgrade_point | 50 | + | id_groupmode | Visible groups | + And I press "Save and display" + + When I follow "Attendance" + Then I click on "Take attendance" "link" in the "01:00 - 02:00" "table_row" + # Excused + And I click on "td.c3 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Add session" + And I set the following fields to these values: + | id_sestime_starthour | 03 | + | id_sestime_endhour | 04 | + | id_sessiontype_1 | 1 | + | id_groups | Group1 | + And I click on "id_submitbutton" "button" + Then I should see "03:00 - 04:00" + And "Group: Group1" "text" should exist in the "03:00 - 04:00" "table_row" + + When I click on "Take attendance" "link" in the "03:00 - 04:00" "table_row" + # Present + And I click on "td.c2 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Report" + Then "Student 1" row "Points" column of "generaltable" table should contain "3 / 4" + And "Student 1" row "Percentage" column of "generaltable" table should contain "75.0%" + + When I follow "Grades" in the user menu + And I follow "Course 1" + Then "37.50" "text" should exist in the "Student 1" "table_row" + + And I log out + + Scenario: Teacher visit summary report + When I log in as "teacher1" + And I follow "Course 1" + And I follow "Attendance" + And I follow "Edit settings" + And I set the following fields to these values: + | id_grade_modgrade_type | Point | + | id_grade_modgrade_point | 50 | + And I press "Save and display" + + When I click on "Take attendance" "link" in the "01:00 - 02:00" "table_row" + # Late + And I click on "td.c3 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Add session" + And I set the following fields to these values: + | id_sestime_starthour | 03 | + | id_sestime_endhour | 04 | + And I click on "id_submitbutton" "button" + Then I should see "03:00 - 04:00" + + When I click on "Take attendance" "link" in the "03:00 - 04:00" "table_row" + # Present + And I click on "td.c2 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Add session" + And I set the following fields to these values: + | id_sestime_starthour | 05 | + | id_sestime_endhour | 06 | + And I click on "id_submitbutton" "button" + Then I should see "05:00 - 06:00" + + When I follow "Report" + And I click on "Summary" "link" in the "All" "table_row" + Then "Student 1" row "Total number of sessions" column of "generaltable" table should contain "3" + And "Student 1" row "Points over all sessions" column of "generaltable" table should contain "3 / 6" + And "Student 1" row "Percentage over all sessions" column of "generaltable" table should contain "50.0%" + And "Student 1" row "Maximum possible points" column of "generaltable" table should contain "5 / 6" + And "Student 1" row "Maximum possible percentage" column of "generaltable" table should contain "83.3%" + + And I log out + + Scenario: Student visit user report + When I log in as "teacher1" + And I follow "Course 1" + And I follow "Attendance" + And I follow "Edit settings" + And I set the following fields to these values: + | id_grade_modgrade_type | Point | + | id_grade_modgrade_point | 50 | + And I press "Save and display" + + When I click on "Take attendance" "link" in the "01:00 - 02:00" "table_row" + # Late + And I click on "td.c3 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Add session" + And I set the following fields to these values: + | id_sestime_starthour | 03 | + | id_sestime_endhour | 04 | + And I click on "id_submitbutton" "button" + + When I click on "Take attendance" "link" in the "03:00 - 04:00" "table_row" + # Present + And I click on "td.c2 input" "css_element" in the "Student 1" "table_row" + And I press "Save attendance" + + When I follow "Add session" + And I set the following fields to these values: + | id_sestime_starthour | 05 | + | id_sestime_endhour | 06 | + And I click on "id_submitbutton" "button" + + Then I log out + + When I log in as "student1" + And I follow "Course 1" + And I follow "Attendance" + And I follow "All" + + Then "2" "text" should exist in the "Taked sessions" "table_row" + And "3 / 4" "text" should exist in the "Points over taked sessions:" "table_row" + And "75.0%" "text" should exist in the "Percentage over taked sessions:" "table_row" + And "3" "text" should exist in the "Total number of sessions:" "table_row" + And "3 / 6" "text" should exist in the "Points over all sessions:" "table_row" + And "50.0%" "text" should exist in the "Percentage over all sessions:" "table_row" + And "5 / 6" "text" should exist in the "Maximum possible points:" "table_row" + And "83.3%" "text" should exist in the "Maximum possible percentage:" "table_row" + + And I log out