source: main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py @ 10322

Last change on this file since 10322 was 10276, checked in by Henrik Bettermann, 11 years ago

Remove gpa field. The GPA must not be an attribute of the level. It contains also information on carry over courses of following levels. Thus it can only be reliably calculated at the end of a study course, e.g. in transcripts.

  • Property svn:keywords set to Id
File size: 22.3 KB
Line 
1## $Id: interfaces.py 10276 2013-06-05 08:02:29Z 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#from datetime import datetime
19from zope.component import getUtility
20from zope.interface import Attribute, Interface
21from zope import schema
22from zc.sourcefactory.contextual import BasicContextualSourceFactory
23from waeup.kofa.browser.interfaces import IStudentNavigationBase
24from waeup.kofa.interfaces import (
25    IKofaObject, academic_sessions_vocab, validate_email, ICSVExporter)
26from waeup.kofa.interfaces import MessageFactory as _
27from waeup.kofa.schema import TextLineChoice, FormattedDate, PhoneNumber
28from waeup.kofa.students.vocabularies import (
29    StudyLevelSource, contextual_reg_num_source, contextual_mat_num_source,
30    GenderSource, nats_vocab
31    )
32from waeup.kofa.payments.interfaces import (
33    IPaymentsContainer, IOnlinePayment)
34from waeup.kofa.university.vocabularies import (
35    CourseSource, StudyModeSource, CertificateSource, SemesterSource,
36    ContextualDictSourceFactoryBase)
37
38class PreviousPaymentCategorySource(ContextualDictSourceFactoryBase):
39    """A source that delivers all selectable categories of previous session
40    payments.
41    """
42    #: name of dict to deliver from kofa utils.
43    DICT_NAME = 'PREVIOUS_PAYMENT_CATEGORIES'
44
45class BalancePaymentCategorySource(ContextualDictSourceFactoryBase):
46    """A source that delivers all selectable items of balance payments.
47    """
48    #: name of dict to deliver from kofa utils.
49    DICT_NAME = 'BALANCE_PAYMENT_CATEGORIES'
50
51# VerdictSource can't be placed into the vocabularies module because it
52# requires importing IStudentsUtils which then leads to circular imports.
53class VerdictSource(BasicContextualSourceFactory):
54    """A verdicts source delivers all verdicts provided
55    in the portal.
56    """
57    def getValues(self, context):
58        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
59        return sorted(verdicts_dict.keys())
60
61    def getToken(self, context, value):
62        return value
63
64    def getTitle(self, context, value):
65        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
66        if value != '0':
67            return verdicts_dict[value] + ' (%s)' % value
68        return verdicts_dict[value]
69
70
71class IStudentsUtils(Interface):
72    """A collection of methods which are subject to customization.
73
74    """
75    def setReturningData(student):
76        """ This method defines what happens after school fee payment
77        depending on the student's senate verdict.
78
79        In the base configuration current level is always increased
80        by 100 no matter which verdict has been assigned.
81        """
82
83    def setPaymentDetails(category, student, previous_session=None,
84            previous_level=None,):
85        """Create Payment object and set the payment data of a student for
86        the payment category specified.
87
88        """
89
90    def getAccommodation_details(student):
91        """Determine the accommodation dates of a student.
92
93        """
94
95    def selectBed(available_beds):
96        """Select a bed from a list of available beds.
97
98        In the standard configuration we select the first bed found,
99        but can also randomize the selection if we like.
100        """
101
102    def getPDFCreator(context):
103        """Get some IPDFCreator instance suitable for use with `context`.
104        """
105
106    def renderPDF(view, subject='', filename='slip.pdf',):
107        """Render pdf slips for various pages.
108
109        """
110
111class IStudentsContainer(IKofaObject):
112    """A students container contains university students.
113
114    """
115    def addStudent(student):
116        """Add an IStudent object and subcontainers.
117
118        """
119
120    def archive(id=None):
121        """Create on-dist archive of students.
122
123        If id is `None`, all students are archived.
124
125        If id contains a single id string, only the respective
126        students are archived.
127
128        If id contains a list of id strings all of the respective
129        students types are saved to disk.
130        """
131
132    def clear(id=None, archive=True):
133        """Remove students of type given by 'id'.
134
135        Optionally archive the students.
136
137        If id is `None`, all students are archived.
138
139        If id contains a single id string, only the respective
140        students are archived.
141
142        If id contains a list of id strings all of the respective
143        student types are saved to disk.
144
145        If `archive` is ``False`` none of the archive-handling is done
146        and respective students are simply removed from the
147        database.
148        """
149
150    unique_student_id = Attribute("""A unique student id.""")
151
152class IStudentNavigation(IStudentNavigationBase):
153    """Interface needed for student navigation, logging, etc.
154
155    """
156    student = Attribute('Student object of context.')
157
158    def writeLogMessage(view, message):
159        """Write a view specific log message into students.log.
160
161        """
162
163class IStudentBase(IKofaObject):
164    """Representation of student base data.
165
166    """
167    history = Attribute('Object history, a list of messages')
168    state = Attribute('Returns the registration state of a student')
169    password = Attribute('Encrypted password of a student')
170    temp_password = Attribute(
171        'Dictionary with user name, timestamp and encrypted password')
172    certcode = Attribute('The certificate code of any chosen study course')
173    depcode = Attribute('The department code of any chosen study course')
174    faccode = Attribute('The faculty code of any chosen study course')
175    entry_session = Attribute('The entry session of the student')
176    current_session = Attribute('The current session of the student')
177    current_level = Attribute('The current level of the student')
178    current_mode = Attribute('The current mode of the student')
179    current_verdict = Attribute('The current verdict of the student')
180    fullname = Attribute('All name parts separated by hyphens')
181    display_fullname = Attribute('The fullname of an applicant')
182    is_postgrad = Attribute('True if postgraduate student')
183
184    suspended = schema.Bool(
185        title = _(u'Account suspended'),
186        default = False,
187        required = False,
188        )
189
190    suspended_comment = schema.Text(
191        title = _(u"Reasons for Deactivation"),
192        required = False,
193        description = _(
194            u'This message will be shown if and only if deactivated '
195            'students try to login.'),
196        )
197
198    student_id = schema.TextLine(
199        title = _(u'Student Id'),
200        required = False,
201        )
202
203    firstname = schema.TextLine(
204        title = _(u'First Name'),
205        required = True,
206        )
207
208    middlename = schema.TextLine(
209        title = _(u'Middle Name'),
210        required = False,
211        )
212
213    lastname = schema.TextLine(
214        title = _(u'Last Name (Surname)'),
215        required = True,
216        )
217
218    sex = schema.Choice(
219        title = _(u'Sex'),
220        source = GenderSource(),
221        required = True,
222        )
223
224    reg_number = TextLineChoice(
225        title = _(u'Registration Number'),
226        required = True,
227        readonly = False,
228        source = contextual_reg_num_source,
229        )
230
231    matric_number = TextLineChoice(
232        title = _(u'Matriculation Number'),
233        required = False,
234        readonly = False,
235        source = contextual_mat_num_source,
236        )
237
238    adm_code = schema.TextLine(
239        title = _(u'PWD Activation Code'),
240        required = False,
241        readonly = False,
242        )
243
244    email = schema.ASCIILine(
245        title = _(u'Email'),
246        required = False,
247        constraint=validate_email,
248        )
249    phone = PhoneNumber(
250        title = _(u'Phone'),
251        description = u'',
252        required = False,
253        )
254
255    def setTempPassword(user, password):
256        """Set a temporary password (LDAP-compatible) SSHA encoded for
257        officers.
258
259        """
260
261    def getTempPassword():
262        """Check if a temporary password has been set and if it
263        is not expired.
264
265        Return the temporary password if valid,
266        None otherwise. Unset the temporary password if expired.
267        """
268
269    def transfer(certificate, current_session,
270        current_level, current_verdict):
271        """ Creates a new studycourse and backups the old one.
272
273        """
274
275class IUGStudentClearance(IKofaObject):
276    """Representation of undergraduate student clearance data.
277
278    """
279    officer_comment = schema.Text(
280        title = _(u"Officer's Comment"),
281        required = False,
282        )
283
284    clearance_locked = schema.Bool(
285        title = _(u'Clearance form locked'),
286        default = False,
287        required = False,
288        )
289
290    clr_code = schema.TextLine(
291        title = _(u'CLR Activation Code'),
292        required = False,
293        readonly = False,
294        )
295
296    date_of_birth = FormattedDate(
297        title = _(u'Date of Birth'),
298        required = True,
299        show_year = True,
300        )
301
302    nationality = schema.Choice(
303        vocabulary = nats_vocab,
304        title = _(u'Nationality'),
305        required = False,
306        )
307
308class IPGStudentClearance(IUGStudentClearance):
309    """Representation of postgraduate student clearance data.
310
311    """
312    employer = schema.TextLine(
313        title = _(u'Employer'),
314        required = False,
315        readonly = False,
316        )
317
318class IStudentPersonal(IKofaObject):
319    """Representation of student personal data.
320
321    """
322    personal_updated = schema.Datetime(
323        title = _(u'Updated'),
324        required = False,
325        readonly = False,
326        )
327
328    perm_address = schema.Text(
329        title = _(u'Permanent Address'),
330        required = False,
331        )
332
333class IStudent(IStudentBase,IUGStudentClearance,IPGStudentClearance,
334    IStudentPersonal):
335    """Representation of a student.
336
337    """
338
339class IStudentPersonalEdit(IStudentPersonal):
340    """Interface for editing personal data by students.
341
342    Here we can repeat the fields from IStudentPersonal and set the
343    `required` if necessary.
344    """
345
346    perm_address = schema.Text(
347        title = _(u'Permanent Address'),
348        required = True,
349        )
350
351class IStudentUpdateByRegNo(IStudent):
352    """Representation of a student. Skip regular reg_number validation.
353
354    """
355    reg_number = schema.TextLine(
356        title = _(u'Registration Number'),
357        required = False,
358        )
359
360class IStudentUpdateByMatricNo(IStudent):
361    """Representation of a student. Skip regular matric_number validation.
362
363    """
364    matric_number = schema.TextLine(
365        title = _(u'Matriculation Number'),
366        required = False,
367        )
368
369class IStudentRequestPW(IStudent):
370    """Representation of an student for first-time password request.
371
372    This interface is used when students use the requestpw page to
373    login for the the first time.
374    """
375    number = schema.TextLine(
376        title = _(u'Registr. or Matric. Number'),
377        required = True,
378        )
379
380    firstname = schema.TextLine(
381        title = _(u'First Name'),
382        required = True,
383        )
384
385    email = schema.ASCIILine(
386        title = _(u'Email Address'),
387        required = True,
388        constraint=validate_email,
389        )
390
391class IStudentStudyCourse(IKofaObject):
392    """A container for student study levels.
393
394    """
395    certificate = schema.Choice(
396        title = _(u'Certificate'),
397        source = CertificateSource(),
398        required = False,
399        )
400
401    entry_mode = schema.Choice(
402        title = _(u'Entry Mode'),
403        source = StudyModeSource(),
404        required = True,
405        readonly = False,
406        )
407
408    entry_session = schema.Choice(
409        title = _(u'Entry Session'),
410        source = academic_sessions_vocab,
411        #default = datetime.now().year,
412        required = True,
413        readonly = False,
414        )
415
416    current_session = schema.Choice(
417        title = _(u'Current Session'),
418        source = academic_sessions_vocab,
419        required = True,
420        readonly = False,
421        )
422
423    current_level = schema.Choice(
424        title = _(u'Current Level'),
425        source = StudyLevelSource(),
426        required = False,
427        readonly = False,
428        )
429
430    current_verdict = schema.Choice(
431        title = _(u'Current Verdict'),
432        source = VerdictSource(),
433        default = '0',
434        required = False,
435        )
436
437    previous_verdict = schema.Choice(
438        title = _(u'Previous Verdict'),
439        source = VerdictSource(),
440        default = '0',
441        required = False,
442        )
443
444class IStudentStudyCourseTransfer(IStudentStudyCourse):
445    """An student transfers.
446
447    """
448
449    certificate = schema.Choice(
450        title = _(u'Certificate'),
451        source = CertificateSource(),
452        required = True,
453        )
454
455    current_level = schema.Choice(
456        title = _(u'Current Level'),
457        source = StudyLevelSource(),
458        required = True,
459        readonly = False,
460        )
461
462    entry_session = schema.Choice(
463        title = _(u'Entry Session'),
464        source = academic_sessions_vocab,
465        #default = datetime.now().year,
466        required = False,
467        readonly = False,
468        )
469
470
471IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
472    'certificate'].order
473IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
474    'current_level'].order
475
476class IStudentStudyCourseTranscript(IKofaObject):
477    """An interface for student transcripts.
478
479    """
480
481    entry_mode = schema.Choice(
482        title = _(u'Entry Mode'),
483        source = StudyModeSource(),
484        required = True,
485        readonly = False,
486        )
487
488    entry_session = schema.Choice(
489        title = _(u'Entry Session'),
490        source = academic_sessions_vocab,
491        #default = datetime.now().year,
492        required = True,
493        readonly = False,
494        )
495
496class IStudentVerdictUpdate(IKofaObject):
497    """A interface for verdict imports.
498
499    """
500
501    current_verdict = schema.Choice(
502        title = _(u'Current Verdict'),
503        source = VerdictSource(),
504        required = True,
505        )
506
507    current_session = schema.Choice(
508        title = _(u'Current Session'),
509        source = academic_sessions_vocab,
510        required = True,
511        )
512
513    current_level = schema.Choice(
514        title = _(u'Current Level'),
515        source = StudyLevelSource(),
516        required = True,
517        )
518
519    bypass_validation = schema.Bool(
520        title = _(u'Bypass validation'),
521        required = False,
522        )
523
524    validated_by = schema.TextLine(
525        title = _(u'Validated by'),
526        required = False,
527        )
528
529class IStudentStudyLevel(IKofaObject):
530    """A container for course tickets.
531
532    """
533    level = Attribute('The level code')
534    number_of_tickets = Attribute('Number of tickets contained in this level')
535    certcode = Attribute('The certificate code of the study course')
536    is_current_level = Attribute('Is this level the current level of the student?')
537
538    level_session = schema.Choice(
539        title = _(u'Session'),
540        source = academic_sessions_vocab,
541        required = True,
542        )
543
544    level_verdict = schema.Choice(
545        title = _(u'Verdict'),
546        source = VerdictSource(),
547        default = '0',
548        required = False,
549        )
550
551    validated_by = schema.TextLine(
552        title = _(u'Validated by'),
553        default = None,
554        required = False,
555        )
556
557    validation_date = schema.Datetime(
558        title = _(u'Validation Date'),
559        required = False,
560        readonly = False,
561        )
562
563    total_credits = schema.Int(
564        title = _(u'Total Credits'),
565        required = False,
566        readonly = True,
567        )
568
569    #gpa = schema.Int(
570    #    title = _(u'GPA'),
571    #    required = False,
572    #    readonly = True,
573    #    )
574
575    def addCourseTicket(ticket, course):
576        """Add a course ticket object.
577        """
578
579    def addCertCourseTickets(cert):
580        """Collect all certificate courses and create course
581        tickets automatically.
582        """
583
584class ICourseTicket(IKofaObject):
585    """An interface for course tickets.
586
587    """
588    code = Attribute('code of the original course')
589    certcode = Attribute('certificate code of the study course')
590    grade = Attribute('grade calculated from score')
591    weight = Attribute('weight calculated from score')
592    removable_by_student = Attribute('Is student allowed to remove the ticket?')
593    level_session = Attribute('session of the level the ticket has been added to')
594    level = Attribute('id of the level the ticket has been added to')
595
596    title = schema.TextLine(
597        title = _(u'Title'),
598        required = False,
599        )
600
601    fcode = schema.TextLine(
602        title = _(u'Faculty Code'),
603        required = False,
604        )
605
606    dcode = schema.TextLine(
607        title = _(u'Department Code'),
608        required = False,
609        )
610
611    semester = schema.Choice(
612        title = _(u'Semester/Term'),
613        source = SemesterSource(),
614        required = False,
615        )
616
617    passmark = schema.Int(
618        title = _(u'Passmark'),
619        required = False,
620        )
621
622    credits = schema.Int(
623        title = _(u'Credits'),
624        required = False,
625        )
626
627    mandatory = schema.Bool(
628        title = _(u'Required'),
629        default = False,
630        required = False,
631        )
632
633    score = schema.Int(
634        title = _(u'Score'),
635        default = None,
636        required = False,
637        )
638
639    carry_over = schema.Bool(
640        title = _(u'Carry-over Course'),
641        default = False,
642        required = False,
643        )
644
645    automatic = schema.Bool(
646        title = _(u'Automatical Creation'),
647        default = False,
648        required = False,
649        )
650
651
652class ICourseTicketAdd(IKofaObject):
653    """An interface for adding course tickets.
654
655    """
656    course = schema.Choice(
657        title = _(u'Course'),
658        source = CourseSource(),
659        readonly = False,
660        )
661
662class ICourseTicketImport(ICourseTicket):
663    """An interface for importing course results and nothing more.
664
665    """
666    score = schema.Int(
667        title = _(u'Score'),
668        required = False,
669        readonly = False,
670        )
671
672    level_session = schema.Choice(
673        title = _(u'Level Session'),
674        source = academic_sessions_vocab,
675        required = False,
676        readonly = False,
677        )
678
679class IStudentAccommodation(IKofaObject):
680    """A container for student accommodation objects.
681
682    """
683
684    def addBedTicket(bedticket):
685        """Add a bed ticket object.
686        """
687
688
689class IBedTicket(IKofaObject):
690    """A ticket for accommodation booking.
691
692    """
693    bed = Attribute('The bed object.')
694
695    bed_coordinates = schema.TextLine(
696        title = u'',
697        required = True,
698        readonly = False,
699        )
700
701    display_coordinates = schema.TextLine(
702        title = _(u'Allocated Bed'),
703        required = False,
704        readonly = True,
705        )
706
707    bed_type = schema.TextLine(
708        title = _(u'Requested Bed Type'),
709        required = True,
710        readonly = False,
711        )
712
713    booking_session = schema.Choice(
714        title = _(u'Session'),
715        source = academic_sessions_vocab,
716        required = True,
717        readonly = True,
718        )
719
720    booking_date = schema.Datetime(
721        title = _(u'Booking Date'),
722        required = False,
723        readonly = True,
724        )
725
726    booking_code = schema.TextLine(
727        title = _(u'Booking Activation Code'),
728        required = False,
729        readonly = True,
730        )
731
732    def getSessionString():
733        """Returns the title of academic_sessions_vocab term.
734
735        """
736
737class IStudentPaymentsContainer(IPaymentsContainer):
738    """A container for student payment objects.
739
740    """
741
742class IStudentOnlinePayment(IOnlinePayment):
743    """A student payment via payment gateways.
744
745    """
746
747    p_current = schema.Bool(
748        title = _(u'Current Session Payment'),
749        default = True,
750        required = False,
751        )
752
753    p_level = schema.Int(
754        title = _(u'Payment Level'),
755        required = False,
756        )
757
758    def doAfterStudentPayment():
759        """Process student after payment was made.
760
761        """
762
763    def doAfterStudentPaymentApproval():
764        """Process student after payment was approved.
765
766        """
767
768    def approveStudentPayment():
769        """Approve payment and process student.
770
771        """
772
773IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
774    'p_session'].order
775
776class IStudentPreviousPayment(IKofaObject):
777    """An interface for adding previous session payments.
778
779    """
780
781    p_category = schema.Choice(
782        title = _(u'Payment Category'),
783        default = u'schoolfee',
784        source = PreviousPaymentCategorySource(),
785        required = True,
786        )
787
788    p_session = schema.Choice(
789        title = _(u'Payment Session'),
790        source = academic_sessions_vocab,
791        required = True,
792        )
793
794    p_level = schema.Choice(
795        title = _(u'Payment Level'),
796        source = StudyLevelSource(),
797        required = True,
798        )
799
800class IStudentBalancePayment(IKofaObject):
801    """An interface for adding balances.
802
803    """
804
805    p_category = schema.Choice(
806        title = _(u'Payment Category'),
807        default = u'schoolfee',
808        required = True,
809        source = BalancePaymentCategorySource(),
810        )
811
812    balance_session = schema.Choice(
813        title = _(u'Payment Session'),
814        source = academic_sessions_vocab,
815        required = True,
816        )
817
818    balance_level = schema.Choice(
819        title = _(u'Payment Level'),
820        source = StudyLevelSource(),
821        required = True,
822        )
823
824    balance_amount = schema.Float(
825        title = _(u'Balance Amount'),
826        default = None,
827        required = True,
828        readonly = False,
829        description = _(
830            u'Balance in Naira '),
831        )
832
833class ICSVStudentExporter(ICSVExporter):
834    """A regular ICSVExporter that additionally supports exporting
835      data from a given student object.
836    """
837    def get_filtered(site, **kw):
838        """Get a filtered set of students.
839        """
840
841    def export_student(student, filepath=None):
842        """Export data for a given student.
843        """
844
845    def export_filtered(site, filepath=None, **kw):
846        """Export filtered set of students.
847        """
Note: See TracBrowser for help on using the repository browser.