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

Last change on this file since 13537 was 13457, checked in by Henrik Bettermann, 9 years ago

Add option which allows students to select a desired hostel before booking accommodation.

  • Property svn:keywords set to Id
File size: 25.2 KB
Line 
1## $Id: interfaces.py 13457 2015-11-16 09:05:30Z 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, IKofaUtils)
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(IKofaUtils).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(IKofaUtils).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    unique_student_id = Attribute("""A unique student id.""")
148
149class IStudentNavigation(IStudentNavigationBase):
150    """Interface needed for navigation and logging. This interface is
151    implemented by all content classes in the students section.
152    """
153    student = Attribute('Student object of context')
154
155    def writeLogMessage(view, message):
156        """Add an INFO message to students.log.
157        """
158
159class IStudentBase(IKofaObject):
160    """Representation of student base data.
161    """
162    history = Attribute('Object history, a list of messages')
163    state = Attribute('Registration state')
164    translated_state = Attribute('Real name of the registration state')
165    certcode = Attribute('Certificate code of any chosen study course')
166    depcode = Attribute('Department code of any chosen study course')
167    faccode = Attribute('Faculty code of any chosen study course')
168    entry_session = Attribute('Entry session')
169    current_session = Attribute('Current session')
170    current_level = Attribute('Current level')
171    current_mode = Attribute('Current mode')
172    current_verdict = Attribute('Current verdict')
173    fullname = Attribute('All name parts separated by hyphens')
174    display_fullname = Attribute('Fullname as displayed on pages')
175    is_postgrad = Attribute('True if postgraduate student')
176    is_special_postgrad = Attribute('True if special postgraduate student')
177    is_fresh = Attribute('True if fresh student')
178    before_payment = Attribute('True if no previous payment has to be made')
179    personal_data_expired = Attribute('True if personal data expired')
180    transcript_enabled = Attribute('True if transcript processing is enabled')
181    clearance_locked = Attribute('True if clearance form is locked')
182
183    password = Attribute('Encrypted password')
184    temp_password = Attribute('Dictionary with user name, timestamp and encrypted password')
185
186    suspended = schema.Bool(
187        title = _(u'Account suspended'),
188        default = False,
189        required = False,
190        )
191
192    suspended_comment = schema.Text(
193        title = _(u"Reasons for Deactivation"),
194        required = False,
195        description = _(
196            u'This message will be shown if and only if deactivated '
197            'students try to login.'),
198        )
199
200    student_id = schema.TextLine(
201        title = _(u'Student Id'),
202        required = False,
203        )
204
205    firstname = schema.TextLine(
206        title = _(u'First Name'),
207        required = True,
208        )
209
210    middlename = schema.TextLine(
211        title = _(u'Middle Name'),
212        required = False,
213        )
214
215    lastname = schema.TextLine(
216        title = _(u'Last Name (Surname)'),
217        required = True,
218        )
219
220    sex = schema.Choice(
221        title = _(u'Sex'),
222        source = GenderSource(),
223        required = True,
224        )
225
226    reg_number = TextLineChoice(
227        title = _(u'Registration Number'),
228        required = True,
229        readonly = False,
230        source = contextual_reg_num_source,
231        )
232
233    matric_number = TextLineChoice(
234        title = _(u'Matriculation Number'),
235        required = False,
236        readonly = False,
237        source = contextual_mat_num_source,
238        )
239
240    adm_code = schema.TextLine(
241        title = _(u'PWD Activation Code'),
242        required = False,
243        readonly = False,
244        )
245
246    email = schema.ASCIILine(
247        title = _(u'Email'),
248        required = False,
249        constraint=validate_email,
250        )
251    phone = PhoneNumber(
252        title = _(u'Phone'),
253        required = False,
254        )
255
256    def setTempPassword(user, password):
257        """Set a temporary password (LDAP-compatible) SSHA encoded for
258        officers.
259        """
260
261    def getTempPassword():
262        """Check if a temporary password has been set and if it
263        is not expired. Return the temporary password if valid,
264        None otherwise. Unset the temporary password if expired.
265        """
266
267    def transfer(certificate, current_session,
268        current_level, current_verdict):
269        """ Creates a new studycourse and backups the old one.
270        """
271
272    def revert_transfer():
273        """ Revert previous transfer.
274        """
275
276class IUGStudentClearance(IKofaObject):
277    """Representation of undergraduate student clearance data.
278    """
279    officer_comment = schema.Text(
280        title = _(u"Officer's Comment"),
281        required = False,
282        )
283
284    clr_code = schema.TextLine(
285        title = _(u'CLR Activation Code'),
286        required = False,
287        readonly = False,
288        )
289
290    date_of_birth = FormattedDate(
291        title = _(u'Date of Birth'),
292        required = True,
293        show_year = True,
294        )
295
296    nationality = schema.Choice(
297        vocabulary = nats_vocab,
298        title = _(u'Nationality'),
299        required = False,
300        )
301
302class IPGStudentClearance(IUGStudentClearance):
303    """Representation of postgraduate student clearance data.
304    """
305    employer = schema.TextLine(
306        title = _(u'Employer'),
307        required = False,
308        readonly = False,
309        )
310
311class IStudentPersonal(IKofaObject):
312    """Representation of student personal data.
313    """
314    personal_updated = schema.Datetime(
315        title = _(u'Updated'),
316        required = False,
317        readonly = False,
318        )
319
320    perm_address = schema.Text(
321        title = _(u'Permanent Address'),
322        required = False,
323        )
324
325class IStudentTranscript(IKofaObject):
326    """Representation of student transcript data.
327    """
328
329    transcript_comment = schema.Text(
330        title = _(u'Comment'),
331        required = False,
332        )
333
334
335class IStudent(IStudentBase,IUGStudentClearance,IPGStudentClearance,
336    IStudentPersonal, IStudentTranscript):
337    """Representation of a student.
338    """
339
340class IStudentPersonalEdit(IStudentPersonal):
341    """Interface for editing personal data by students.
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    reg_number = schema.TextLine(
355        title = _(u'Registration Number'),
356        required = False,
357        )
358
359class IStudentUpdateByMatricNo(IStudent):
360    """Representation of a student. Skip regular matric_number validation.
361    """
362    matric_number = schema.TextLine(
363        title = _(u'Matriculation Number'),
364        required = False,
365        )
366
367class IStudentRequestPW(IStudent):
368    """Representation of a student for first-time password request.
369    This interface is used when students use the requestpw page to
370    login for the the first time.
371    """
372    number = schema.TextLine(
373        title = _(u'Registr. or Matric. Number'),
374        required = True,
375        )
376
377    firstname = schema.TextLine(
378        title = _(u'First Name'),
379        required = True,
380        )
381
382    email = schema.ASCIILine(
383        title = _(u'Email Address'),
384        required = True,
385        constraint=validate_email,
386        )
387
388class IStudentStudyCourse(IKofaObject):
389    """Representation of student study course data.
390    """
391    next_session_allowed = Attribute('True if the student can proceed to next session')
392    is_postgrad = Attribute('True if student is postgraduate student')
393    is_current = Attribute('True if the study course is the current course of studies')
394    is_previous = Attribute('True if the study course is the previous course of studies')
395
396    certificate = schema.Choice(
397        title = _(u'Certificate'),
398        source = CertificateSource(),
399        required = False,
400        )
401
402    entry_mode = schema.Choice(
403        title = _(u'Entry Mode'),
404        source = StudyModeSource(),
405        required = True,
406        readonly = False,
407        )
408
409    entry_session = schema.Choice(
410        title = _(u'Entry Session'),
411        source = academic_sessions_vocab,
412        #default = datetime.now().year,
413        required = True,
414        readonly = False,
415        )
416
417    current_session = schema.Choice(
418        title = _(u'Current Session'),
419        source = academic_sessions_vocab,
420        required = True,
421        readonly = False,
422        )
423
424    current_level = schema.Choice(
425        title = _(u'Current Level'),
426        source = StudyLevelSource(),
427        required = False,
428        readonly = False,
429        )
430
431    current_verdict = schema.Choice(
432        title = _(u'Current Verdict'),
433        source = VerdictSource(),
434        default = '0',
435        required = False,
436        )
437
438    previous_verdict = schema.Choice(
439        title = _(u'Previous Verdict'),
440        source = VerdictSource(),
441        default = '0',
442        required = False,
443        )
444
445    def addStudentStudyLevel(cert, studylevel):
446        """Add a study level object.
447        """
448
449    def getTranscriptData():
450        """Get a sorted list of dicts with level and course ticket data.
451        This method is used for transcripts.
452        """
453
454class IStudentStudyCourseTransfer(IStudentStudyCourse):
455    """An interface used for student transfers.
456    """
457    certificate = schema.Choice(
458        title = _(u'Certificate'),
459        source = CertificateSource(),
460        required = True,
461        )
462
463    current_level = schema.Choice(
464        title = _(u'Current Level'),
465        source = StudyLevelSource(),
466        required = True,
467        readonly = False,
468        )
469
470    entry_session = schema.Choice(
471        title = _(u'Entry Session'),
472        source = academic_sessions_vocab,
473        #default = datetime.now().year,
474        required = False,
475        readonly = False,
476        )
477
478
479IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
480    'certificate'].order
481IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
482    'current_level'].order
483
484class IStudentStudyCourseTranscript(IKofaObject):
485    """An interface for student transcripts.
486    """
487    entry_mode = schema.Choice(
488        title = _(u'Entry Mode'),
489        source = StudyModeSource(),
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 = True,
499        readonly = False,
500        )
501
502class IStudentVerdictUpdate(IKofaObject):
503    """A interface for verdict imports.
504    """
505    current_verdict = schema.Choice(
506        title = _(u'Current Verdict'),
507        source = VerdictSource(),
508        required = True,
509        )
510
511    current_session = schema.Choice(
512        title = _(u'Current Session'),
513        source = academic_sessions_vocab,
514        required = True,
515        )
516
517    current_level = schema.Choice(
518        title = _(u'Current Level'),
519        source = StudyLevelSource(),
520        required = True,
521        )
522
523    bypass_validation = schema.Bool(
524        title = _(u'Bypass validation'),
525        required = False,
526        )
527
528    validated_by = schema.TextLine(
529        title = _(u'Validated by'),
530        required = False,
531        )
532
533class IStudentStudyLevel(IKofaObject):
534    """A representation of student study level data.
535    """
536    certcode = Attribute('The certificate code of the study course')
537    is_current_level = Attribute('True if level is current level of the student')
538    level_title = Attribute('Level title from source')
539    getSessionString = Attribute('Session title from source')
540    number_of_tickets = Attribute('Number of tickets contained in this level')
541    passed_params = Attribute('Information about passed and failed courses')
542    gpa_params_rectified = Attribute('Corrected sessional GPA parameters')
543    gpa_params = Attribute('GPA parameters for this level.')
544    cumulative_params = Attribute('Cumulative GPA and other cumulative parameters for this level')
545    course_registration_allowed = Attribute('True if registerin courses is allowed')
546
547    level = schema.Choice(
548        title = _(u'Level'),
549        source = StudyLevelSource(),
550        required = True,
551        readonly = False,
552        )
553
554    level_session = schema.Choice(
555        title = _(u'Session'),
556        source = academic_sessions_vocab,
557        required = True,
558        )
559
560    level_verdict = schema.Choice(
561        title = _(u'Verdict'),
562        source = VerdictSource(),
563        default = '0',
564        required = False,
565        )
566
567    validated_by = schema.TextLine(
568        title = _(u'Validated by'),
569        default = None,
570        required = False,
571        )
572
573    validation_date = schema.Datetime(
574        title = _(u'Validation Date'),
575        required = False,
576        readonly = False,
577        )
578
579    total_credits = schema.Int(
580        title = _(u'Total Credits'),
581        required = False,
582        readonly = True,
583        )
584
585    gpa = schema.Int(
586        title = _(u'Unrectified GPA'),
587        required = False,
588        readonly = True,
589        )
590
591    def addCourseTicket(ticket, course):
592        """Add a course ticket object.
593        """
594
595    def addCertCourseTickets(cert):
596        """Collect all certificate courses and create course
597        tickets automatically.
598        """
599
600class ICourseTicket(IKofaObject):
601    """A representation of course ticket data.
602    """
603    certcode = Attribute('Certificate code of the study course')
604    level_session = Attribute('Session of the study level the ticket has been added to')
605    level = Attribute('Level value of the study level the ticket has been added to')
606    grade = Attribute('Grade calculated from score')
607    weight = Attribute('Weight calculated from score')
608    removable_by_student = Attribute('True if student is allowed to remove the ticket')
609    editable_by_lecturer = Attribute('True if lecturer is allowed to edit the ticket')
610
611    code = Attribute('Code of the original course')
612
613    title = schema.TextLine(
614        title = _(u'Title'),
615        required = False,
616        )
617
618    fcode = schema.TextLine(
619        title = _(u'Faculty Code'),
620        required = False,
621        )
622
623    dcode = schema.TextLine(
624        title = _(u'Department Code'),
625        required = False,
626        )
627
628    semester = schema.Choice(
629        title = _(u'Semester/Term'),
630        source = SemesterSource(),
631        required = False,
632        )
633
634    passmark = schema.Int(
635        title = _(u'Passmark'),
636        required = False,
637        )
638
639    credits = schema.Int(
640        title = _(u'Credits'),
641        required = False,
642        )
643
644    mandatory = schema.Bool(
645        title = _(u'Required'),
646        default = False,
647        required = False,
648        )
649
650    score = schema.Int(
651        title = _(u'Score'),
652        default = None,
653        required = False,
654        missing_value = None,
655        )
656
657    carry_over = schema.Bool(
658        title = _(u'Carry-over Course'),
659        default = False,
660        required = False,
661        )
662
663    automatic = schema.Bool(
664        title = _(u'Automatical Creation'),
665        default = False,
666        required = False,
667        )
668
669class ICourseTicketAdd(IKofaObject):
670    """An interface for adding course tickets.
671    """
672    course = schema.Choice(
673        title = _(u'Course'),
674        source = CourseSource(),
675        readonly = False,
676        )
677
678class ICourseTicketImport(ICourseTicket):
679    """An interface for importing course results and nothing more.
680    """
681    score = schema.Int(
682        title = _(u'Score'),
683        required = False,
684        readonly = False,
685        )
686
687    level_session = schema.Choice(
688        title = _(u'Level Session'),
689        source = academic_sessions_vocab,
690        required = False,
691        readonly = False,
692        )
693
694class IStudentAccommodation(IKofaObject):
695    """A container for student accommodation objects.
696    """
697
698    desired_hostel = schema.TextLine(
699        title = _(u'Desired Hostel'),
700        required = False,
701        )
702
703    def addBedTicket(bedticket):
704        """Add a bed ticket object.
705        """
706
707
708class IBedTicket(IKofaObject):
709    """A representation of accommodation booking data.
710    """
711    bed = Attribute('The bed object')
712    maint_payment_made = Attribute('True if maintenance payment is made')
713
714    display_coordinates = schema.TextLine(
715        title = _(u'Allocated Bed'),
716        required = False,
717        readonly = True,
718        )
719
720    bed_coordinates = schema.TextLine(
721        title = u'',
722        required = True,
723        readonly = False,
724        )
725
726    bed_type = schema.TextLine(
727        title = _(u'Requested Bed Type'),
728        required = True,
729        readonly = False,
730        )
731
732    booking_session = schema.Choice(
733        title = _(u'Session'),
734        source = academic_sessions_vocab,
735        required = True,
736        readonly = False
737        )
738
739    booking_date = schema.Datetime(
740        title = _(u'Booking Date'),
741        required = False,
742        readonly = False,
743        )
744
745    booking_code = schema.TextLine(
746        title = _(u'Booking Activation Code'),
747        required = False,
748        readonly = False,
749        )
750
751    def getSessionString():
752        """Returns the title of academic_sessions_vocab term of the session
753        when the bed was booked.
754        """
755
756class IStudentPaymentsContainer(IPaymentsContainer):
757    """A container for student payment objects.
758    """
759
760class IStudentOnlinePayment(IOnlinePayment):
761    """A student payment via payment gateways.
762    """
763
764    p_current = schema.Bool(
765        title = _(u'Current Session Payment'),
766        default = True,
767        required = False,
768        )
769
770    p_level = schema.Int(
771        title = _(u'Payment Level'),
772        required = False,
773        )
774
775    def doAfterStudentPayment():
776        """Process student after payment was made.
777        """
778
779    def doAfterStudentPaymentApproval():
780        """Process student after payment was approved.
781        """
782
783    def approveStudentPayment():
784        """Approve payment and process student.
785        """
786
787IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
788    'p_session'].order
789
790class IStudentPreviousPayment(IKofaObject):
791    """An interface for adding previous session payments.
792    """
793
794    p_category = schema.Choice(
795        title = _(u'Payment Category'),
796        default = u'schoolfee',
797        source = PreviousPaymentCategorySource(),
798        required = True,
799        )
800
801    p_session = schema.Choice(
802        title = _(u'Payment Session'),
803        source = academic_sessions_vocab,
804        required = True,
805        )
806
807    p_level = schema.Choice(
808        title = _(u'Payment Level'),
809        source = StudyLevelSource(),
810        required = True,
811        )
812
813class IStudentBalancePayment(IKofaObject):
814    """An interface for adding balances.
815    """
816
817    p_category = schema.Choice(
818        title = _(u'Payment Category'),
819        default = u'schoolfee',
820        required = True,
821        source = BalancePaymentCategorySource(),
822        )
823
824    balance_session = schema.Choice(
825        title = _(u'Payment Session'),
826        source = academic_sessions_vocab,
827        required = True,
828        )
829
830    balance_level = schema.Choice(
831        title = _(u'Payment Level'),
832        source = StudyLevelSource(),
833        required = True,
834        )
835
836    balance_amount = schema.Float(
837        title = _(u'Balance Amount'),
838        default = None,
839        required = True,
840        readonly = False,
841        description = _(
842            u'Balance in Naira '),
843        )
844
845class ICSVStudentExporter(ICSVExporter):
846    """A regular ICSVExporter that additionally supports exporting
847      data from a given student object.
848    """
849    def get_filtered(site, **kw):
850        """Get a filtered set of students.
851        """
852
853    def get_selected(site, selected):
854        """Get set of selected students.
855        """
856
857    def export_student(student, filepath=None):
858        """Export data for a given student.
859        """
860
861    def export_filtered(site, filepath=None, **kw):
862        """Export data for filtered set of students.
863        """
864
865    def export_selected(site, filepath=None, **kw):
866        """Export data for selected set of students.
867        """
Note: See TracBrowser for help on using the repository browser.