source: main/waeup.kofa/trunk/src/waeup/kofa/students/studylevel.py @ 9966

Last change on this file since 9966 was 9925, checked in by Henrik Bettermann, 12 years ago

Convert getLevel and getLevelSession into property attributes.

  • Property svn:keywords set to Id
File size: 7.5 KB
Line 
1## $Id: studylevel.py 9925 2013-01-30 09:08:39Z 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 a student study level
20and contains the course tickets.
21"""
22import grok
23from zope.component.interfaces import IFactory
24from zope.component import createObject
25from zope.interface import implementedBy
26from waeup.kofa.interfaces import academic_sessions_vocab
27from waeup.kofa.students.interfaces import (
28    IStudentStudyLevel, IStudentNavigation, ICourseTicket)
29from waeup.kofa.utils.helpers import attrs_to_fields
30from waeup.kofa.students.vocabularies import StudyLevelSource
31
32def getGradeWeightFromScore(score):
33    if score is None:
34        return (None, None)
35    if score >= 70:
36        return ('A',5)
37    if score >= 60:
38        return ('B',4)
39    if score >= 50:
40        return ('C',3)
41    if score >= 45:
42        return ('D',2)
43    if score >= 40:
44        return ('E',1)
45    return ('F',0)
46
47class StudentStudyLevel(grok.Container):
48    """This is a container for course tickets.
49    """
50    grok.implements(IStudentStudyLevel, IStudentNavigation)
51    grok.provides(IStudentStudyLevel)
52
53    def __init__(self):
54        super(StudentStudyLevel, self).__init__()
55        self.level = None
56        return
57
58    @property
59    def student(self):
60        try:
61            return self.__parent__.__parent__
62        except AttributeError:
63            return None
64
65    @property
66    def certcode(self):
67        try:
68            return self.__parent__.certificate.code
69        except AttributeError:
70            return None
71
72    @property
73    def number_of_tickets(self):
74        return len(self)
75
76    @property
77    def total_credits(self):
78        total = 0
79        for ticket in self.values():
80            total += ticket.credits
81        return total
82
83    @property
84    def getSessionString(self):
85        return academic_sessions_vocab.getTerm(
86            self.level_session).title
87
88    @property
89    def gpa(self):
90        gpa = 0.0
91        credits_counted = 0
92        for ticket in self.values():
93            if ticket.score:
94                credits_counted += ticket.credits
95                gpa += ticket.credits * ticket.weight
96        if credits_counted:
97            gpa = round(gpa/credits_counted, 2)
98        return gpa
99
100    @property
101    def is_current_level(self):
102        try:
103            return self.__parent__.current_level == self.level
104        except AttributeError:
105            return False
106
107    def writeLogMessage(self, view, message):
108        return self.__parent__.__parent__.writeLogMessage(view, message)
109
110    @property
111    def level_title(self):
112        studylevelsource = StudyLevelSource()
113        return studylevelsource.factory.getTitle(self.__parent__, self.level)
114
115    def addCourseTicket(self, ticket, course):
116        """Add a course ticket object.
117        """
118        if not ICourseTicket.providedBy(ticket):
119            raise TypeError(
120                'StudentStudyLeves contain only ICourseTicket instances')
121        ticket.code = course.code
122        ticket.title = course.title
123        ticket.fcode = course.__parent__.__parent__.__parent__.code
124        ticket.dcode = course.__parent__.__parent__.code
125        ticket.credits = course.credits
126        ticket.passmark = course.passmark
127        ticket.semester = course.semester
128        self[ticket.code] = ticket
129        return
130
131    def addCertCourseTickets(self, cert):
132        """Collect all certificate courses and create course
133        tickets automatically.
134        """
135        if cert is not None:
136            for key, val in cert.items():
137                if val.level != self.level:
138                    continue
139                ticket = createObject(u'waeup.CourseTicket')
140                ticket.automatic = True
141                ticket.mandatory = val.mandatory
142                ticket.carry_over = False
143                self.addCourseTicket(ticket, val.course)
144        return
145
146StudentStudyLevel = attrs_to_fields(
147    StudentStudyLevel, omit=['total_credits', 'gpa'])
148
149class StudentStudyLevelFactory(grok.GlobalUtility):
150    """A factory for student study levels.
151    """
152    grok.implements(IFactory)
153    grok.name(u'waeup.StudentStudyLevel')
154    title = u"Create a new student study level.",
155    description = u"This factory instantiates new student study level instances."
156
157    def __call__(self, *args, **kw):
158        return StudentStudyLevel()
159
160    def getInterfaces(self):
161        return implementedBy(StudentStudyLevel)
162
163class CourseTicket(grok.Model):
164    """This is a course ticket which allows the
165    student to attend the course. Lecturers will enter scores and more at
166    the end of the term.
167
168    A course ticket contains a copy of the original course and
169    certificate course data. If the courses and/or the referrin certificate
170    courses are removed, the corresponding tickets remain unchanged.
171    So we do not need any event
172    triggered actions on course tickets.
173    """
174    grok.implements(ICourseTicket, IStudentNavigation)
175    grok.provides(ICourseTicket)
176
177    def __init__(self):
178        super(CourseTicket, self).__init__()
179        self.code = None
180        return
181
182    @property
183    def student(self):
184        """Get the associated student object.
185        """
186        try:
187            return self.__parent__.__parent__.__parent__
188        except AttributeError:
189            return None
190
191    @property
192    def certcode(self):
193        try:
194            return self.__parent__.__parent__.certificate.code
195        except AttributeError:
196            return None
197
198    @property
199    def removable_by_student(self):
200        return not self.mandatory
201
202    def writeLogMessage(self, view, message):
203        return self.__parent__.__parent__.__parent__.writeLogMessage(view, message)
204
205    @property
206    def level(self):
207        """Returns the id of the level the ticket has been added to.
208        """
209        try:
210            return self.__parent__.level
211        except AttributeError:
212            return None
213
214    @property
215    def level_session(self):
216        """Returns the session of the level the ticket has been added to.
217        """
218        try:
219            return self.__parent__.level_session
220        except AttributeError:
221            return None
222
223    @property
224    def grade(self):
225        """Returns the grade calculated from score.
226        """
227        return getGradeWeightFromScore(self.score)[0]
228
229    @property
230    def weight(self):
231        """Returns the weight calculated from score.
232        """
233        return getGradeWeightFromScore(self.score)[1]
234
235CourseTicket = attrs_to_fields(CourseTicket)
236
237class CourseTicketFactory(grok.GlobalUtility):
238    """A factory for student study levels.
239    """
240    grok.implements(IFactory)
241    grok.name(u'waeup.CourseTicket')
242    title = u"Create a new course ticket.",
243    description = u"This factory instantiates new course ticket instances."
244
245    def __call__(self, *args, **kw):
246        return CourseTicket()
247
248    def getInterfaces(self):
249        return implementedBy(CourseTicket)
Note: See TracBrowser for help on using the repository browser.