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

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

Use new attrs_to_fields function to display gpa and total_credits on level pages.

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