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

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

Convert level into a schema field to be consistent with the documentation.

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