Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace gradepenalty_duedate;
18
 
19
use cm_info;
20
use context_course;
21
use context_module;
22
use context_system;
23
use core_grades\penalty_container;
24
 
25
/**
26
 * Penalty plugins must override this class to implement their own penalty calculation.
27
 *
28
 * @package   gradepenalty_duedate
29
 * @copyright 2024 Catalyst IT Australia Pty Ltd
30
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31
 */
32
class penalty_calculator extends \core_grades\penalty_calculator {
33
    /**
34
     * Calculate the penalty for the given activity.
35
     *
36
     * @param penalty_container $container The penalty container.
37
     */
38
    public static function calculate_penalty(penalty_container $container): void {
39
        // Calculate the deducted grade based on the max grade.
40
        $gradeitem = $container->get_grade_item();
41
        $modinfo = get_fast_modinfo($gradeitem->courseid);
42
        $cm = $modinfo->instances[$gradeitem->itemmodule][$gradeitem->iteminstance];
43
        $deductedpercentage = self::get_penalty_from_rules($cm, $container->get_submission_date(), $container->get_due_date());
44
        $deductedgrade = $container->get_max_grade() * $deductedpercentage / 100;
45
        $container->aggregate_penalty($deductedgrade);
46
    }
47
 
48
    /**
49
     * Get the penalty percentage from the most appropriate penalty rule based on the submission date and the due date.
50
     *
51
     * @param cm_info $cm The course module object.
52
     * @param int $submissiondate The submission date.
53
     * @param int $duedate The due date.
54
     * @return float the deducted percentage.
55
     */
56
    public static function get_penalty_from_rules(cm_info $cm, int $submissiondate, int $duedate): float {
57
        // Get the difference between the submission date and the due date.
58
        $diff = $submissiondate - $duedate;
59
 
60
        // Return if the due date is after the submission date.
61
        if ($diff <= 0) {
62
            return 0;
63
        }
64
 
65
        // Get all penalty rules, ordered by the highest penalty first.
66
        $penaltyrules = self::find_effective_penalty_rules($cm);
67
 
68
        // Return if there are no penalty rules.
69
        if (empty($penaltyrules)) {
70
            return 0;
71
        }
72
 
73
        // Return the first applicable penalty rule.
74
        foreach ($penaltyrules as $penaltyrule) {
75
            if ($diff <= $penaltyrule->get('overdueby')) {
76
                return $penaltyrule->get('penalty');
77
            }
78
        }
79
 
80
        // Return the last penalty rule if the difference exceeds the overdueby value of the last rule.
81
        $lastrule = end($penaltyrules);
82
        if ($diff > $lastrule->get('overdueby')) {
83
            return $lastrule->get('penalty');
84
        }
85
 
86
        // Return if no penalty rule is applicable.
87
        return 0;
88
    }
89
 
90
    /**
91
     * Find effective penalty rule which will be applied the course module.
92
     *
93
     * @param cm_info $cm The course module object.
94
     * @return array
95
     */
96
    private static function find_effective_penalty_rules(cm_info $cm): array {
97
        // Course module context id.
98
        $modulecontext = context_module::instance($cm->id);
99
        $coursecontext = context_course::instance($cm->course);
100
        $systemcontext = context_system::instance();
101
 
102
        $contextids = [
103
            $modulecontext->id,
104
            $coursecontext->id,
105
            $systemcontext->id,
106
        ];
107
 
108
        // Get all penalty rules in one query.
109
        $select = 'contextid IN (?, ?, ?)';
110
        $penaltyrules = penalty_rule::get_records_select($select, $contextids, 'sortorder');
111
 
112
        // Filter the penalty rules based on the context hierarchy.
113
        foreach ($contextids as $contextid) {
114
            $rules = array_filter($penaltyrules, function ($penaltyrule) use ($contextid): bool {
115
                return (int) $penaltyrule->get('contextid') === (int) $contextid;
116
            });
117
 
118
            if (!empty($rules)) {
119
                return $rules;
120
            }
121
        }
122
 
123
        return [];
124
    }
125
}