## $Id: studylevel.py 9812 2012-12-20 06:59:26Z henrik $ ## ## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## """ Container which holds the data of a student study level and contains the course tickets. """ import grok from zope.component.interfaces import IFactory from zope.component import createObject from zope.interface import implementedBy from waeup.kofa.students.interfaces import ( IStudentStudyLevel, IStudentNavigation, ICourseTicket) from waeup.kofa.utils.helpers import attrs_to_fields from waeup.kofa.students.vocabularies import StudyLevelSource def getGradeWeightFromScore(score): if score is None: return (None, None) if score >= 70: return ('A',5) if score >= 60: return ('B',4) if score >= 50: return ('C',3) if score >= 45: return ('D',2) if score >= 40: return ('E',1) return ('F',0) class StudentStudyLevel(grok.Container): """This is a container for course tickets. """ grok.implements(IStudentStudyLevel, IStudentNavigation) grok.provides(IStudentStudyLevel) def __init__(self): super(StudentStudyLevel, self).__init__() self.level = None return @property def student(self): try: return self.__parent__.__parent__ except AttributeError: return None @property def certcode(self): try: return self.__parent__.certificate.code except AttributeError: return None @property def number_of_tickets(self): return len(self) @property def total_credits(self): total = 0 for ticket in self.values(): total += ticket.credits return total @property def gpa(self): gpa = 0.0 credits_counted = 0 for ticket in self.values(): if ticket.score: credits_counted += ticket.credits gpa += ticket.credits * ticket.weight if credits_counted: gpa = round(gpa/credits_counted, 2) return gpa @property def is_current_level(self): try: return self.__parent__.current_level == self.level except AttributeError: return False def writeLogMessage(self, view, message): return self.__parent__.__parent__.writeLogMessage(view, message) @property def level_title(self): studylevelsource = StudyLevelSource() return studylevelsource.factory.getTitle(self.__parent__, self.level) def addCourseTicket(self, ticket, course): """Add a course ticket object. """ if not ICourseTicket.providedBy(ticket): raise TypeError( 'StudentStudyLeves contain only ICourseTicket instances') ticket.code = course.code ticket.title = course.title ticket.fcode = course.__parent__.__parent__.__parent__.code ticket.dcode = course.__parent__.__parent__.code ticket.credits = course.credits ticket.passmark = course.passmark ticket.semester = course.semester self[ticket.code] = ticket return def addCertCourseTickets(self, cert): """Collect all certificate courses and create course tickets automatically. """ if cert is not None: for key, val in cert.items(): if val.level != self.level: continue ticket = createObject(u'waeup.CourseTicket') ticket.automatic = True ticket.mandatory = val.mandatory ticket.carry_over = False self.addCourseTicket(ticket, val.course) return StudentStudyLevel = attrs_to_fields( StudentStudyLevel, omit=['total_credits', 'gpa']) class StudentStudyLevelFactory(grok.GlobalUtility): """A factory for student study levels. """ grok.implements(IFactory) grok.name(u'waeup.StudentStudyLevel') title = u"Create a new student study level.", description = u"This factory instantiates new student study level instances." def __call__(self, *args, **kw): return StudentStudyLevel() def getInterfaces(self): return implementedBy(StudentStudyLevel) class CourseTicket(grok.Model): """This is a course ticket which allows the student to attend the course. Lecturers will enter scores and more at the end of the term. A course ticket contains a copy of the original course and certificate course data. If the courses and/or the referrin certificate courses are removed, the corresponding tickets remain unchanged. So we do not need any event triggered actions on course tickets. """ grok.implements(ICourseTicket, IStudentNavigation) grok.provides(ICourseTicket) def __init__(self): super(CourseTicket, self).__init__() self.code = None return @property def student(self): """Get the associated student object. """ try: return self.__parent__.__parent__.__parent__ except AttributeError: return None @property def certcode(self): try: return self.__parent__.__parent__.certificate.code except AttributeError: return None @property def removable_by_student(self): return not self.mandatory def writeLogMessage(self, view, message): return self.__parent__.__parent__.__parent__.writeLogMessage(view, message) def getLevel(self): """Returns the id of the level the ticket has been added to. """ # XXX: shouldn't that be an attribute? try: return self.__parent__.level except AttributeError: return None def getLevelSession(self): """Returns the session of the level the ticket has been added to. """ # XXX: shouldn't that be an attribute? try: return self.__parent__.level_session except AttributeError: return None @property def grade(self): """Returns the grade calculated from score. """ return getGradeWeightFromScore(self.score)[0] @property def weight(self): """Returns the weight calculated from score. """ return getGradeWeightFromScore(self.score)[1] CourseTicket = attrs_to_fields(CourseTicket) class CourseTicketFactory(grok.GlobalUtility): """A factory for student study levels. """ grok.implements(IFactory) grok.name(u'waeup.CourseTicket') title = u"Create a new course ticket.", description = u"This factory instantiates new course ticket instances." def __call__(self, *args, **kw): return CourseTicket() def getInterfaces(self): return implementedBy(CourseTicket)