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

Last change on this file since 11587 was 11450, checked in by Henrik Bettermann, 11 years ago

Move ContextualDictSourceFactoryBase? to waeup.kofa.interfaces to avoid circular imports.

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