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

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

Add exporter methods and export page to filter student data exports by entering a list of student ids.

  • Property svn:keywords set to Id
File size: 23.7 KB
Line 
1## $Id: interfaces.py 12518 2015-01-27 14:48:22Z 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    level = Attribute('The level code')
565    number_of_tickets = Attribute('Number of tickets contained in this level')
566    certcode = Attribute('The certificate code of the study course')
567    is_current_level = Attribute('Is this level the current level of the student?')
568    passed_params = Attribute('Information about passed and failed courses')
569
570    level_session = schema.Choice(
571        title = _(u'Session'),
572        source = academic_sessions_vocab,
573        required = True,
574        )
575
576    level_verdict = schema.Choice(
577        title = _(u'Verdict'),
578        source = VerdictSource(),
579        default = '0',
580        required = False,
581        )
582
583    validated_by = schema.TextLine(
584        title = _(u'Validated by'),
585        default = None,
586        required = False,
587        )
588
589    validation_date = schema.Datetime(
590        title = _(u'Validation Date'),
591        required = False,
592        readonly = False,
593        )
594
595    total_credits = schema.Int(
596        title = _(u'Total Credits'),
597        required = False,
598        readonly = True,
599        )
600
601    gpa = schema.Int(
602        title = _(u'Unrectified GPA'),
603        required = False,
604        readonly = True,
605        )
606
607    def addCourseTicket(ticket, course):
608        """Add a course ticket object.
609        """
610
611    def addCertCourseTickets(cert):
612        """Collect all certificate courses and create course
613        tickets automatically.
614        """
615
616class ICourseTicket(IKofaObject):
617    """An interface for course tickets.
618
619    """
620    code = Attribute('code of the original course')
621    certcode = Attribute('certificate code of the study course')
622    grade = Attribute('grade calculated from score')
623    weight = Attribute('weight calculated from score')
624    removable_by_student = Attribute('Is student allowed to remove the ticket?')
625    level_session = Attribute('session of the level the ticket has been added to')
626    level = Attribute('id of the level the ticket has been added to')
627
628    title = schema.TextLine(
629        title = _(u'Title'),
630        required = False,
631        )
632
633    fcode = schema.TextLine(
634        title = _(u'Faculty Code'),
635        required = False,
636        )
637
638    dcode = schema.TextLine(
639        title = _(u'Department Code'),
640        required = False,
641        )
642
643    semester = schema.Choice(
644        title = _(u'Semester/Term'),
645        source = SemesterSource(),
646        required = False,
647        )
648
649    passmark = schema.Int(
650        title = _(u'Passmark'),
651        required = False,
652        )
653
654    credits = schema.Int(
655        title = _(u'Credits'),
656        required = False,
657        )
658
659    mandatory = schema.Bool(
660        title = _(u'Required'),
661        default = False,
662        required = False,
663        )
664
665    score = schema.Int(
666        title = _(u'Score'),
667        default = None,
668        required = False,
669        missing_value = None,
670        )
671
672    carry_over = schema.Bool(
673        title = _(u'Carry-over Course'),
674        default = False,
675        required = False,
676        )
677
678    automatic = schema.Bool(
679        title = _(u'Automatical Creation'),
680        default = False,
681        required = False,
682        )
683
684
685class ICourseTicketAdd(IKofaObject):
686    """An interface for adding course tickets.
687
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    """
699    score = schema.Int(
700        title = _(u'Score'),
701        required = False,
702        readonly = False,
703        )
704
705    level_session = schema.Choice(
706        title = _(u'Level Session'),
707        source = academic_sessions_vocab,
708        required = False,
709        readonly = False,
710        )
711
712class IStudentAccommodation(IKofaObject):
713    """A container for student accommodation objects.
714
715    """
716
717    def addBedTicket(bedticket):
718        """Add a bed ticket object.
719        """
720
721
722class IBedTicket(IKofaObject):
723    """A ticket for accommodation booking.
724
725    """
726    bed = Attribute('The bed object.')
727
728    bed_coordinates = schema.TextLine(
729        title = u'',
730        required = True,
731        readonly = False,
732        )
733
734    display_coordinates = schema.TextLine(
735        title = _(u'Allocated Bed'),
736        required = False,
737        readonly = True,
738        )
739
740    bed_type = schema.TextLine(
741        title = _(u'Requested Bed Type'),
742        required = True,
743        readonly = False,
744        )
745
746    booking_session = schema.Choice(
747        title = _(u'Session'),
748        source = academic_sessions_vocab,
749        required = True,
750        readonly = True,
751        )
752
753    booking_date = schema.Datetime(
754        title = _(u'Booking Date'),
755        required = False,
756        readonly = True,
757        )
758
759    booking_code = schema.TextLine(
760        title = _(u'Booking Activation Code'),
761        required = False,
762        readonly = True,
763        )
764
765    def getSessionString():
766        """Returns the title of academic_sessions_vocab term.
767
768        """
769
770class IStudentPaymentsContainer(IPaymentsContainer):
771    """A container for student payment objects.
772
773    """
774
775class IStudentOnlinePayment(IOnlinePayment):
776    """A student payment via payment gateways.
777
778    """
779
780    p_current = schema.Bool(
781        title = _(u'Current Session Payment'),
782        default = True,
783        required = False,
784        )
785
786    p_level = schema.Int(
787        title = _(u'Payment Level'),
788        required = False,
789        )
790
791    def doAfterStudentPayment():
792        """Process student after payment was made.
793
794        """
795
796    def doAfterStudentPaymentApproval():
797        """Process student after payment was approved.
798
799        """
800
801    def approveStudentPayment():
802        """Approve payment and process student.
803
804        """
805
806IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
807    'p_session'].order
808
809class IStudentPreviousPayment(IKofaObject):
810    """An interface for adding previous session payments.
811
812    """
813
814    p_category = schema.Choice(
815        title = _(u'Payment Category'),
816        default = u'schoolfee',
817        source = PreviousPaymentCategorySource(),
818        required = True,
819        )
820
821    p_session = schema.Choice(
822        title = _(u'Payment Session'),
823        source = academic_sessions_vocab,
824        required = True,
825        )
826
827    p_level = schema.Choice(
828        title = _(u'Payment Level'),
829        source = StudyLevelSource(),
830        required = True,
831        )
832
833class IStudentBalancePayment(IKofaObject):
834    """An interface for adding balances.
835
836    """
837
838    p_category = schema.Choice(
839        title = _(u'Payment Category'),
840        default = u'schoolfee',
841        required = True,
842        source = BalancePaymentCategorySource(),
843        )
844
845    balance_session = schema.Choice(
846        title = _(u'Payment Session'),
847        source = academic_sessions_vocab,
848        required = True,
849        )
850
851    balance_level = schema.Choice(
852        title = _(u'Payment Level'),
853        source = StudyLevelSource(),
854        required = True,
855        )
856
857    balance_amount = schema.Float(
858        title = _(u'Balance Amount'),
859        default = None,
860        required = True,
861        readonly = False,
862        description = _(
863            u'Balance in Naira '),
864        )
865
866class ICSVStudentExporter(ICSVExporter):
867    """A regular ICSVExporter that additionally supports exporting
868      data from a given student object.
869    """
870    def get_filtered(site, **kw):
871        """Get a filtered set of students.
872        """
873
874    def get_selected(site, selected):
875        """Get set of selected students.
876        """
877
878    def export_student(student, filepath=None):
879        """Export data for a given student.
880        """
881
882    def export_filtered(site, filepath=None, **kw):
883        """Export data for filtered set of students.
884        """
885
886    def export_selected(site, filepath=None, **kw):
887        """Export data for selected set of students.
888        """
Note: See TracBrowser for help on using the repository browser.