source: main/waeup.kofa/branches/uli-fix-zc-async/src/waeup/kofa/students/studycourse.py @ 17389

Last change on this file since 17389 was 16901, checked in by Henrik Bettermann, 3 years ago

Consider course_category in addStudentStudyLevel` method.

  • Property svn:keywords set to Id
File size: 6.6 KB
Line 
1## $Id: studycourse.py 16901 2022-03-23 07:05:20Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program 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 2 of the License, or
7## (at your option) any later version.
8##
9## This program 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 this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Container which holds the data of the student study courses
20and contains the (student) study level objects.
21"""
22import grok
23from zope.component.interfaces import IFactory
24from zope.component import createObject
25from zope.interface import implementedBy
26from waeup.kofa.students.interfaces import (
27    IStudentStudyCourse, IStudentNavigation, IStudentStudyLevel)
28from waeup.kofa.students.studylevel import CourseTicket
29from waeup.kofa.students.workflow import CLEARED, RETURNING, PAID
30from waeup.kofa.utils.helpers import attrs_to_fields
31
32class StudentStudyCourse(grok.Container):
33    """This is a container for study levels.
34    """
35    grok.implements(IStudentStudyCourse, IStudentNavigation)
36    grok.provides(IStudentStudyCourse)
37
38    is_special_postgrad = False
39
40    def __init__(self):
41        super(StudentStudyCourse, self).__init__()
42        return
43
44    @property
45    def student(self):
46        return self.__parent__
47
48    def writeLogMessage(self, view, message):
49        return self.__parent__.writeLogMessage(view, message)
50
51    @property
52    def next_session_allowed(self):
53        certificate = getattr(self, 'certificate', None)
54        if certificate == None:
55            return False
56        if self.student.state in (CLEARED, RETURNING):
57            return True
58        if self.student.state == PAID \
59            and self.student.is_postgrad:
60            return True
61        return False
62
63    @property
64    def is_postgrad(self):
65        if self.certificate is None:
66            return False
67        return self.certificate.study_mode.startswith('pg')
68
69    @property
70    def is_current(self):
71        if self.__name__ and '_' in self.__name__:
72            return False
73        return True
74
75    @property
76    def is_previous(self):
77        if self.__name__ == 'studycourse_2':
78            return True
79        if self.__name__ == 'studycourse_1' and  \
80            not self.__parent__.has_key('studycourse_2'):
81            return True
82        return False
83
84    def addStudentStudyLevel(self, cert, studylevel, course_category=None):
85        """Add a study level object.
86        """
87        if not IStudentStudyLevel.providedBy(studylevel):
88            raise TypeError(
89                'StudentStudyCourses contain only IStudentStudyLevel instances')
90        self[str(studylevel.level)] = studylevel
91        studylevel.addCertCourseTickets(cert)
92        # Collect carry-over courses in base levels (not in repeating levels)
93        try:
94            co_enabled = grok.getSite()['configuration'].carry_over
95        except TypeError:
96            # In tests we might not have a site object
97            co_enabled = True
98        if not co_enabled or studylevel.level % 100 != 0:
99            return
100        levels = sorted(self.keys())
101        index = levels.index(str(studylevel.level))
102        if index <= 0:
103            return
104        previous_level = self[levels[index-1]]
105        for key, val in previous_level.items():
106            if val.total_score >= val.passmark:
107                continue
108            if course_category and val.course_category != course_category:
109                continue
110            if key in self[str(studylevel.level)]:
111                # Carry-over ticket exists
112                continue
113            co_ticket = createObject(u'waeup.CourseTicket')
114            for name in ['code', 'title', 'credits', 'passmark',
115                         'semester', 'mandatory', 'fcode', 'dcode',
116                         'course_category']:
117                setattr(co_ticket, name, getattr(val, name))
118            co_ticket.automatic = True
119            co_ticket.carry_over = True
120            self[str(studylevel.level)][co_ticket.code] = co_ticket
121        return
122
123    def getTranscriptData(self):
124        """Get a sorted list of dicts with level and course ticket data.
125
126        This method is used for transcripts.
127        """
128        levels = []
129        cgpa = 0.0
130        total_credits_counted = 0
131        for level_key, level_val in self.items():
132            # Skip Level Zero
133            if level_key == '0':
134                continue
135            tickets_1 = []
136            tickets_2 = []
137            tickets_3 = []
138            tickets = sorted(level_val.values(), key=lambda ticket: ticket.code)
139            for ticket in tickets:
140                if ticket.outstanding:
141                    continue
142                if ticket.total_score is None:
143                    continue
144                if ticket.semester == 1:
145                    tickets_1.append(ticket)
146                elif ticket.semester == 2:
147                    tickets_2.append(ticket)
148                elif ticket.semester == 3:
149                    tickets_3.append(ticket)
150            gpa_params = level_val.gpa_params_rectified
151            sgpa = gpa_params[0]
152            total_credits_counted += gpa_params[1]
153            cgpa += gpa_params[2]
154            levels.append(
155                dict(level_key=level_key,
156                     level=level_val,
157                     tickets_1=tickets_1,
158                     tickets_2=tickets_2,
159                     tickets_3=tickets_3,
160                     sgpa=sgpa))
161        if total_credits_counted:
162            cgpa = cgpa/total_credits_counted
163        # Override cgpa if value has been imported
164        # (not implemented in base package)
165        imported_cgpa = getattr(self, 'imported_cgpa', None)
166        if imported_cgpa:
167            cgpa = imported_cgpa
168        return sorted(levels, key=lambda level: level['level_key']), cgpa
169
170StudentStudyCourse = attrs_to_fields(StudentStudyCourse)
171
172class StudentStudyCourseFactory(grok.GlobalUtility):
173    """A factory for student study courses.
174    """
175    grok.implements(IFactory)
176    grok.name(u'waeup.StudentStudyCourse')
177    title = u"Create a new student study course.",
178    description = u"This factory instantiates new student study course instances."
179
180    def __call__(self, *args, **kw):
181        return StudentStudyCourse()
182
183    def getInterfaces(self):
184        return implementedBy(StudentStudyCourse)
Note: See TracBrowser for help on using the repository browser.