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

Last change on this file since 13001 was 12999, checked in by Henrik Bettermann, 10 years ago

More docs.

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