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

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

We don't need to edit next_matric_integer in the base package.

Adjust interface.

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