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

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

Remove total_credits method from view. This is already done in the content class.

Calculate momentary gpa and show on level page.

  • Property svn:keywords set to Id
File size: 7.2 KB
Line 
1## $Id: studylevel.py 9687 2012-11-19 18: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.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 = float(gpa)/credits_counted
92        return gpa
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(StudentStudyLevel)
141
142class StudentStudyLevelFactory(grok.GlobalUtility):
143    """A factory for student study levels.
144    """
145    grok.implements(IFactory)
146    grok.name(u'waeup.StudentStudyLevel')
147    title = u"Create a new student study level.",
148    description = u"This factory instantiates new student study level instances."
149
150    def __call__(self, *args, **kw):
151        return StudentStudyLevel()
152
153    def getInterfaces(self):
154        return implementedBy(StudentStudyLevel)
155
156class CourseTicket(grok.Model):
157    """This is a course ticket which allows the
158    student to attend the course. Lecturers will enter scores and more at
159    the end of the term.
160
161    A course ticket contains a copy of the original course and
162    certificate course data. If the courses and/or the referrin certificate
163    courses are removed, the corresponding tickets remain unchanged.
164    So we do not need any event
165    triggered actions on course tickets.
166    """
167    grok.implements(ICourseTicket, IStudentNavigation)
168    grok.provides(ICourseTicket)
169
170    def __init__(self):
171        super(CourseTicket, self).__init__()
172        self.code = None
173        return
174
175    @property
176    def student(self):
177        """Get the associated student object.
178        """
179        try:
180            return self.__parent__.__parent__.__parent__
181        except AttributeError:
182            return None
183
184    @property
185    def certcode(self):
186        try:
187            return self.__parent__.__parent__.certificate.code
188        except AttributeError:
189            return None
190
191    def writeLogMessage(self, view, message):
192        return self.__parent__.__parent__.__parent__.writeLogMessage(view, message)
193
194    def getLevel(self):
195        """Returns the id of the level the ticket has been added to.
196        """
197        # XXX: shouldn't that be an attribute?
198        try:
199            return self.__parent__.level
200        except AttributeError:
201            return None
202
203    def getLevelSession(self):
204        """Returns the session of the level the ticket has been added to.
205        """
206        # XXX: shouldn't that be an attribute?
207        try:
208            return self.__parent__.level_session
209        except AttributeError:
210            return None
211
212    @property
213    def grade(self):
214        """Returns the grade calculated from score.
215        """
216        return getGradeWeightFromScore(self.score)[0]
217
218    @property
219    def weight(self):
220        """Returns the weight calculated from score.
221        """
222        return getGradeWeightFromScore(self.score)[1]
223
224CourseTicket = attrs_to_fields(CourseTicket)
225
226class CourseTicketFactory(grok.GlobalUtility):
227    """A factory for student study levels.
228    """
229    grok.implements(IFactory)
230    grok.name(u'waeup.CourseTicket')
231    title = u"Create a new course ticket.",
232    description = u"This factory instantiates new course ticket instances."
233
234    def __call__(self, *args, **kw):
235        return CourseTicket()
236
237    def getInterfaces(self):
238        return implementedBy(CourseTicket)
Note: See TracBrowser for help on using the repository browser.