source: main/waeup.uniben/trunk/src/waeup/uniben/applicants/interfaces.py @ 16700

Last change on this file since 16700 was 16471, checked in by Henrik Bettermann, 4 years ago

Add two fields to transcript application.

  • Property svn:keywords set to Id
File size: 22.4 KB
RevLine 
[13814]1# -*- coding: utf-8 -*-
[7853]2## $Id: interfaces.py 16471 2021-04-20 07:16:10Z henrik $
3##
4## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
5## This program is free software; you can redistribute it and/or modify
6## it under the terms of the GNU General Public License as published by
7## the Free Software Foundation; either version 2 of the License, or
8## (at your option) any later version.
9##
10## This program is distributed in the hope that it will be useful,
11## but WITHOUT ANY WARRANTY; without even the implied warranty of
12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13## GNU General Public License for more details.
14##
15## You should have received a copy of the GNU General Public License
16## along with this program; if not, write to the Free Software
17## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18##
19"""Customized interfaces of the university application package.
20"""
21
[13831]22#from grok import getSite
[8012]23from zope import schema
[13831]24#from zope.interface import invariant, Invalid
[16152]25from zope.component import getUtility
26from zope.catalog.interfaces import ICatalog
[13814]27from zc.sourcefactory.basic import BasicSourceFactory
[8051]28from waeup.kofa.applicants.interfaces import (
[8053]29    IApplicantBaseData,
[8051]30    AppCatCertificateSource, CertificateSource)
[16078]31from waeup.kofa.university.vocabularies import StudyModeSource
32from waeup.kofa.students.vocabularies import (
33    nats_vocab, GenderSource, StudyLevelSource)
[8051]34from waeup.kofa.schoolgrades import ResultEntryField
[8530]35from waeup.kofa.interfaces import (
[13814]36    SimpleKofaVocabulary, academic_sessions_vocab, validate_email,
[16131]37    IKofaObject, ContextualDictSourceFactoryBase)
[13814]38from waeup.kofa.schema import FormattedDate, TextLineChoice, PhoneNumber
[15490]39from waeup.kofa.students.vocabularies import (
40    nats_vocab, GenderSource)
[14106]41from waeup.kofa.refereeentries import RefereeEntryField
[8530]42from waeup.kofa.applicants.interfaces import contextual_reg_num_source
[15490]43from kofacustom.nigeria.interfaces import DisabilitiesSource
[8928]44from kofacustom.nigeria.applicants.interfaces import (
45    LGASource, high_qual, high_grade, exam_types,
[14140]46    programme_types_vocab, jambsubjects,
[8928]47    INigeriaUGApplicant, INigeriaPGApplicant,
48    INigeriaApplicantOnlinePayment,
[9006]49    INigeriaUGApplicantEdit, INigeriaPGApplicantEdit,
50    INigeriaApplicantUpdateByRegNo,
51    IPUTMEApplicantEdit,
[14140]52    IBankAccount,
[8928]53    )
[8020]54from waeup.uniben.interfaces import MessageFactory as _
[8247]55from waeup.uniben.payments.interfaces import ICustomOnlinePayment
[7853]56
[16152]57class TranscriptCertificateSource(CertificateSource):
58    """Include Department and Faculty in Title.
59    """
60    def getValues(self, context):
61        catalog = getUtility(ICatalog, name='certificates_catalog')
62        resultset = catalog.searchResults(code=(None, None))
63        resultlist = sorted(resultset, key=lambda
64            value: value.__parent__.__parent__.__parent__.code +
65            value.__parent__.__parent__.code +
66            value.code)
67        return resultlist
[13814]68
[16152]69    def getTitle(self, context, value):
70        """
71        """
72        try: title = "%s / %s / %s (%s)" % (
73            value.__parent__.__parent__.__parent__.title,
74            value.__parent__.__parent__.title,
75            value.title, value.code)
76        except AttributeError:
77            title = "NA / %s (%s)" % (value.title, value.code)
78        return title
79
[13814]80REGISTRATION_CATS = {
81    'corporate': ('Corporate Registration', 250000, 1),
82    'group': ('Group Registration', 200000, 2),
83    'individual': ('Individual Registration', 45000, 3),
84    'student': ('Student Registration', 5000, 4),
[13824]85    'fullpage': ('Full Page Advert', 250000, 5),
86    'halfpage': ('Half Page Advert', 150000, 6),
87    'quarterpage': ('Quarter Page Advert', 100000, 7),
[13814]88    }
89
90class RegTypesSource(BasicSourceFactory):
91    """A source that delivers all kinds of registrations.
92    """
93    def getValues(self):
94        sorted_items = sorted(REGISTRATION_CATS.items(),
95                              key=lambda element: element[1][2])
96        return [item[0] for item in sorted_items]
97
98    def getTitle(self, value):
99        return u"%s @ ₦ %s" % (
100            REGISTRATION_CATS[value][0],
101            REGISTRATION_CATS[value][1])
102
[16131]103DESTINATION_COST = {
[16144]104    #'none': ('To the moon', 1000000000.0, 1),
105    'nigeria': ('Within Nigeria', 20000.0, 1),
106    'africa': ('Within Africa ', 30000.0, 2),
107    'inter': ('International', 35000.0, 3),
[16182]108    'cert_nigeria': ('Certified Copy - Within Nigeria', 13000.0, 4),
109    'cert_africa': ('Certified Copy - Within Africa', 23000.0, 5),
110    'cert_inter': ('Certified Copy - International', 28000.0, 6),
[16131]111    }
112
113class DestinationCostSource(BasicSourceFactory):
114    """A source that delivers continents and shipment costs.
115    """
116    def getValues(self):
117        sorted_items = sorted(DESTINATION_COST.items(),
118                              key=lambda element: element[1][2])
119        return [item[0] for item in sorted_items]
120
[16151]121    def getToken(self, value):
122        return value
123
[16131]124    def getTitle(self, value):
125        return u"%s (₦ %s)" % (
126            DESTINATION_COST[value][0],
127            DESTINATION_COST[value][1])
128
[16151]129class OrderSource(BasicSourceFactory):
130    """
131    """
132    def getValues(self):
133        return ['o', 'c']
134
135    def getToken(self, value):
136        return value
137
138    def getTitle(self, value):
139        if value == 'o':
140            return _('Original')
141        if value == 'c':
142            return _('Certified True Copy')
143
[13814]144class IUnibenRegistration(IKofaObject):
145    """A Uniben registrant.
146    """
147
148    suspended = schema.Bool(
149        title = _(u'Account suspended'),
150        default = False,
151        required = False,
152        )
153
154    locked = schema.Bool(
155        title = _(u'Form locked'),
156        default = False,
157        required = False,
158        )
159
160    applicant_id = schema.TextLine(
161        title = _(u'Registrant Id'),
162        required = False,
163        readonly = False,
164        )
165
166    firstname = schema.TextLine(
167        title = _(u'First Name'),
168        required = True,
169        )
170
171    middlename = schema.TextLine(
172        title = _(u'Middle Name'),
173        required = False,
174        )
175
176    lastname = schema.TextLine(
177        title = _(u'Last Name (Surname)'),
178        required = True,
179        )
180
[13819]181    sex = schema.Choice(
182        title = _(u'Sex'),
183        source = GenderSource(),
184        required = True,
[13814]185        )
186
187    nationality = schema.Choice(
188        vocabulary = nats_vocab,
189        title = _(u'Nationality'),
190        required = False,
191        )
192
193    email = schema.ASCIILine(
194        title = _(u'Email Address'),
195        required = True,
196        constraint=validate_email,
197        )
198
199    phone = PhoneNumber(
200        title = _(u'Phone'),
201        description = u'',
202        required = False,
203        )
204
[13819]205    #perm_address = schema.Text(
206    #    title = _(u'Current Local Address'),
207    #    required = False,
208    #    readonly = False,
209    #    )
210
211    institution = schema.TextLine(
212        title = _(u'Institution/Organisation'),
[13814]213        required = False,
214        readonly = False,
215        )
216
[13828]217    city = schema.TextLine(
218        title = _(u'City'),
219        required = False,
220        readonly = False,
221        )
222
[13819]223    lga = schema.Choice(
224        source = LGASource(),
225        title = _(u'State/LGA'),
226        required = False,
227        )
228
[13831]229    matric_number = schema.TextLine(
230        title = _(u'Uniben Matriculation Number'),
231        required = False,
232        readonly = False,
233        )
234
[13814]235    registration_cats = schema.List(
236        title = _(u'Registration Categories'),
237        value_type = schema.Choice(source=RegTypesSource()),
238        required = True,
[14020]239        defaultFactory=list,
[13814]240        )
241
[13831]242#    @invariant
243#    def matric_number_exists(applicant):
244#        if applicant.matric_number:
245#            catalog = getUtility(ICatalog, name='students_catalog')
246#            accommodation_session = getSite()['hostels'].accommodation_session
247#            student = catalog.searchResults(matric_number=(
248#                applicant.matric_number, applicant.matric_number))
249#            if len(student) != 1:
250#                raise Invalid(_("Matriculation number not found."))
[13814]251
[16078]252class ITranscriptApplicant(IKofaObject):
253    """A transcript applicant.
254    """
255
256    suspended = schema.Bool(
257        title = _(u'Account suspended'),
258        default = False,
259        required = False,
260        )
261
262    locked = schema.Bool(
263        title = _(u'Form locked'),
264        default = False,
265        required = False,
266        )
267
268    applicant_id = schema.TextLine(
[16131]269        title = _(u'Transcript Application Id'),
[16078]270        required = False,
271        readonly = False,
272        )
273
[16131]274    student_id = schema.TextLine(
275        title = _(u'Kofa Student Id'),
276        required = False,
[16078]277        readonly = False,
[16131]278        )
279
280    matric_number = schema.TextLine(
281        title = _(u'Matriculation Number'),
282        readonly = False,
[16078]283        required = True,
284        )
285
286    firstname = schema.TextLine(
[16151]287        title = _(u'First Name in School'),
[16078]288        required = True,
289        )
290
291    middlename = schema.TextLine(
[16151]292        title = _(u'Middle Name in School'),
[16078]293        required = False,
294        )
295
296    lastname = schema.TextLine(
[16151]297        title = _(u'Surname in School'),
[16078]298        required = True,
299        )
300
301    date_of_birth = FormattedDate(
302        title = _(u'Date of Birth'),
303        required = False,
304        #date_format = u'%d/%m/%Y', # Use grok-instance-wide default
305        show_year = True,
306        )
307
308    sex = schema.Choice(
309        title = _(u'Gender'),
310        source = GenderSource(),
311        required = True,
312        )
313
[16151]314    #nationality = schema.Choice(
315    #    vocabulary = nats_vocab,
316    #    title = _(u'Nationality'),
317    #    required = False,
318    #    )
[16078]319
320    email = schema.ASCIILine(
321        title = _(u'Email Address'),
322        required = True,
323        constraint=validate_email,
324        )
325
326    phone = PhoneNumber(
327        title = _(u'Phone'),
328        description = u'',
329        required = False,
330        )
331
[16151]332    #perm_address = schema.Text(
333    #    title = _(u'Current Local Address'),
334    #    required = False,
335    #    readonly = False,
336    #    )
337
[16153]338    collected = schema.Bool(
339        title = _(u'Have you collected transcript before?'),
340        default = False,
341        required = False,
342        )
343
[16151]344    entry_session = schema.Choice(
345        title = _(u'Academic Session of Entry'),
346        source = academic_sessions_vocab,
[16078]347        required = False,
348        readonly = False,
349        )
350
[16151]351    end_session = schema.Choice(
352        title = _(u'Academic Session of Graduation'),
353        source = academic_sessions_vocab,
[16078]354        required = False,
355        readonly = False,
356        )
357
358    entry_mode = schema.Choice(
[16151]359        title = _(u'Mode of Entry'),
[16078]360        source = StudyModeSource(),
361        required = False,
362        readonly = False,
363        )
364
365    course_studied = schema.Choice(
[16151]366        title = _(u'Course of Study'),
[16152]367        source = TranscriptCertificateSource(),
[16201]368        description = u'Faculty / Department / Course',
[16376]369        required = True,
[16078]370        readonly = False,
371        )
372
373    course_changed = schema.Choice(
[16151]374        title = _(u'Change of Study Course / Transfer'),
[16078]375        description = u'If yes, select previous course of study.',
[16152]376        source = TranscriptCertificateSource(),
[16078]377        readonly = False,
378        required = False,
379        )
380
[16153]381    spillover_level = schema.Choice(
382        title = _(u'Spill-over'),
383        description = u'Any spill-over? If yes, select session of spill-over.',
384        source = academic_sessions_vocab,
385        required = False,
386        readonly = False,
387        )
[16151]388
389    purpose = schema.TextLine(
390        title = _(u'Transcript Purpose'),
[16078]391        required = False,
[16151]392        )
393
394    order = schema.Choice(
395        source = OrderSource(),
396        title = _(u'Type of Order'),
397        required = False,
398        )
399
400    dispatch_address = schema.Text(
401        title = _(u'Recipient Body'),
402        description = u'Addresses (including email address and phone number) '
403                       'to which transcripts should be posted. '
404                       'All addresses must involve same courier charges.',
[16307]405        required = True,
[16078]406        readonly = False,
407        )
408
[16151]409    charge = schema.Choice(
[16182]410        title = _(u'Transcript Charge'),
[16151]411        source = DestinationCostSource(),
[16198]412        required = False,
413        readonly = False,
[16151]414        )
415
[16078]416    no_copies = schema.Choice(
417        title = _(u'Number of Copies'),
418        description = u'Must correspond with the number of dispatch addresses above.',
419        values=[1, 2, 3, 4],
420        required = False,
421        readonly = False,
422        default = 1,
423        )
424
[16471]425    courier_tno = schema.TextLine(
426        title = _(u'Courier Tracking Number'),
427        required = False,
428        )
429
430    proc_date = FormattedDate(
431        title = _(u'Processing Date'),
432        required = False,
433        #date_format = u'%d/%m/%Y', # Use grok-instance-wide default
434        show_year = True,
435        )
436
437
[14140]438class ICustomUGApplicant(IApplicantBaseData, IBankAccount):
[8012]439    """An undergraduate applicant.
440
[8519]441    This interface defines the least common multiple of all fields
442    in ug application forms. In customized forms, fields can be excluded by
443    adding them to the UG_OMIT* tuples.
[8012]444    """
445
[15490]446    disabilities = schema.Choice(
447        title = _(u'Disabilities'),
448        source = DisabilitiesSource(),
449        required = False,
450        )
[14140]451    nationality = schema.Choice(
452        source = nats_vocab,
453        title = _(u'Nationality'),
454        required = False,
455        )
456    lga = schema.Choice(
457        source = LGASource(),
458        title = _(u'State/LGA (Nigerians only)'),
459        required = False,
460        )
461    #perm_address = schema.Text(
462    #    title = _(u'Permanent Address'),
463    #    required = False,
464    #    )
465    course1 = schema.Choice(
466        title = _(u'1st Choice Course of Study'),
467        source = AppCatCertificateSource(),
468        required = True,
469        )
470    course2 = schema.Choice(
471        title = _(u'2nd Choice Course of Study'),
472        source = AppCatCertificateSource(),
473        required = False,
474        )
475
476    programme_type = schema.Choice(
477        title = _(u'Programme Type'),
478        vocabulary = programme_types_vocab,
479        required = False,
480        )
481
482    hq_type = schema.Choice(
483        title = _(u'Qualification Obtained'),
484        required = False,
485        readonly = False,
486        vocabulary = high_qual,
487        )
488    hq_matric_no = schema.TextLine(
489        title = _(u'Former Matric Number'),
490        required = False,
491        readonly = False,
492        )
493    hq_degree = schema.Choice(
494        title = _(u'Class of Degree'),
495        required = False,
496        readonly = False,
497        vocabulary = high_grade,
498        )
499    hq_school = schema.TextLine(
500        title = _(u'Institution Attended'),
501        required = False,
502        readonly = False,
503        )
504    hq_session = schema.TextLine(
505        title = _(u'Years Attended'),
506        required = False,
507        readonly = False,
508        )
509    hq_disc = schema.TextLine(
510        title = _(u'Discipline'),
511        required = False,
512        readonly = False,
513        )
[14141]514    fst_sit_fname = schema.TextLine(
515        title = _(u'Full Name'),
516        required = False,
517        readonly = False,
518        )
519    fst_sit_no = schema.TextLine(
520        title = _(u'Exam Number'),
521        required = False,
522        readonly = False,
523        )
524    fst_sit_date = FormattedDate(
525        title = _(u'Exam Date'),
526        required = False,
527        readonly = False,
528        show_year = True,
529        )
530    fst_sit_type = schema.Choice(
531        title = _(u'Exam Type'),
532        required = False,
533        readonly = False,
534        vocabulary = exam_types,
535        )
536    fst_sit_results = schema.List(
537        title = _(u'Exam Results'),
538        value_type = ResultEntryField(),
539        required = False,
540        readonly = False,
541        defaultFactory=list,
542        )
543    scd_sit_fname = schema.TextLine(
544        title = _(u'Full Name'),
545        required = False,
546        readonly = False,
547        )
548    scd_sit_no = schema.TextLine(
549        title = _(u'Exam Number'),
550        required = False,
551        readonly = False,
552        )
553    scd_sit_date = FormattedDate(
554        title = _(u'Exam Date'),
555        required = False,
556        readonly = False,
557        show_year = True,
558        )
559    scd_sit_type = schema.Choice(
560        title = _(u'Exam Type'),
561        required = False,
562        readonly = False,
563        vocabulary = exam_types,
564        )
565    scd_sit_results = schema.List(
566        title = _(u'Exam Results'),
567        value_type = ResultEntryField(),
568        required = False,
569        readonly = False,
570        defaultFactory=list,
571        )
[14140]572    jamb_subjects = schema.Text(
573        title = _(u'Subjects and Scores'),
574        required = False,
575        )
576    jamb_subjects_list = schema.List(
577        title = _(u'JAMB Subjects'),
578        required = False,
579        defaultFactory=list,
580        value_type = schema.Choice(
581            vocabulary = jambsubjects
582            #source = JAMBSubjectSource(),
583            ),
584        )
585    jamb_score = schema.Int(
586        title = _(u'Total JAMB Score'),
587        required = False,
588        )
589    #jamb_age = schema.Int(
590    #    title = _(u'Age (provided by JAMB)'),
591    #    required = False,
592    #    )
593    jamb_reg_number = schema.TextLine(
594        title = _(u'JAMB Registration Number'),
595        required = False,
596        )
597    notice = schema.Text(
598        title = _(u'Notice'),
599        required = False,
600        )
601    screening_venue = schema.TextLine(
602        title = _(u'Screening Venue'),
603        required = False,
604        )
605    screening_date = schema.TextLine(
606        title = _(u'Screening Date'),
607        required = False,
608        )
609    screening_score = schema.Int(
610        title = _(u'Screening Score (%)'),
611        required = False,
612        )
613    aggregate = schema.Int(
614        title = _(u'Aggregate Score (%)'),
615        description = _(u'(average of relative JAMB and PUTME scores)'),
616        required = False,
617        )
618    result_uploaded = schema.Bool(
619        title = _(u'Result uploaded'),
620        default = False,
621        required = False,
622        )
623    student_id = schema.TextLine(
624        title = _(u'Student Id'),
625        required = False,
626        readonly = False,
627        )
628    course_admitted = schema.Choice(
629        title = _(u'Admitted Course of Study'),
630        source = CertificateSource(),
631        required = False,
632        )
633    locked = schema.Bool(
634        title = _(u'Form locked'),
635        default = False,
636        required = False,
637        )
638
639ICustomUGApplicant[
640    'locked'].order =  IApplicantBaseData['suspended'].order
641ICustomUGApplicant[
642    'result_uploaded'].order =  ICustomUGApplicant['suspended'].order
643
[8928]644class ICustomPGApplicant(INigeriaPGApplicant):
[7853]645    """A postgraduate applicant.
646
[8519]647    This interface defines the least common multiple of all fields
648    in pg application forms. In customized forms, fields can be excluded by
649    adding them to the PG_OMIT* tuples.
[7866]650    """
651
[14106]652    referees = schema.List(
653        title = _(u'Referees'),
654        value_type = RefereeEntryField(),
655        required = False,
656        defaultFactory=list,
657        )
[8012]658
[14106]659ICustomPGApplicant[
660    'referees'].order =  INigeriaPGApplicant['emp2_reason'].order
661
[13814]662class ICustomApplicant(ICustomUGApplicant, ICustomPGApplicant,
[16078]663    IUnibenRegistration, ITranscriptApplicant):
[8012]664    """An interface for both types of applicants.
665
[8928]666    Attention: The ICustomPGApplicant field seetings will be overwritten
667    by ICustomPGApplicant field settings. If a field is defined
[8727]668    in both interfaces zope.schema validates only against the
[8928]669    constraints in ICustomUGApplicant. This does not affect the forms
670    since they are build on either ICustomUGApplicant or ICustomPGApplicant.
[8012]671    """
672
[8743]673    def writeLogMessage(view, comment):
[8053]674        """Adds an INFO message to the log file
675        """
676
677    def createStudent():
[8668]678        """Create a student object from applicant data
[8053]679        and copy applicant object.
680        """
681
[14212]682class ICustomUGApplicantEdit(ICustomUGApplicant):
[8727]683    """An undergraduate applicant interface for edit forms.
[8012]684
685    Here we can repeat the fields from base data and set the
686    `required` and `readonly` attributes to True to further restrict
687    the data access. Or we can allow only certain certificates to be
688    selected by choosing the appropriate source.
689
690    We cannot omit fields here. This has to be done in the
691    respective form page.
692    """
693
[14212]694    email = schema.ASCIILine(
695        title = _(u'Email Address'),
696        required = True,
697        constraint=validate_email,
698        )
699    date_of_birth = FormattedDate(
700        title = _(u'Date of Birth'),
701        required = True,
702        show_year = True,
703        )
704
705ICustomUGApplicantEdit[
706    'date_of_birth'].order = ICustomUGApplicant['date_of_birth'].order
707ICustomUGApplicantEdit[
708    'email'].order = ICustomUGApplicant['email'].order
709
[9056]710class ICustomPGApplicantEdit(INigeriaPGApplicantEdit):
[7866]711    """A postgraduate applicant interface for editing.
712
713    Here we can repeat the fields from base data and set the
714    `required` and `readonly` attributes to True to further restrict
715    the data access. Or we can allow only certain certificates to be
716    selected by choosing the appropriate source.
717
718    We cannot omit fields here. This has to be done in the
719    respective form page.
[8017]720    """
[8454]721
[14106]722    referees = schema.List(
723        title = _(u'Referees'),
724        value_type = RefereeEntryField(),
725        required = False,
726        defaultFactory=list,
727        )
[13814]728
[14106]729ICustomPGApplicantEdit[
730    'referees'].order =  INigeriaPGApplicantEdit['emp2_reason'].order
731
[8928]732class ICustomApplicantOnlinePayment(INigeriaApplicantOnlinePayment):
[8247]733    """An applicant payment via payment gateways.
734
735    """
[8530]736
[14153]737class IPUTMEApplicantEdit(ICustomUGApplicant):
[8530]738    """An undergraduate applicant interface for editing.
739
740    Here we can repeat the fields from base data and set the
741    `required` and `readonly` attributes to True to further restrict
742    the data access. Or we can allow only certain certificates to be
743    selected by choosing the appropriate source.
744
745    We cannot omit fields here. This has to be done in the
746    respective form page.
747    """
748
[14153]749    email = schema.ASCIILine(
750        title = _(u'Email Address'),
751        required = True,
752        constraint=validate_email,
753        )
754    date_of_birth = FormattedDate(
755        title = _(u'Date of Birth'),
756        required = True,
757        show_year = True,
758        )
759    nationality = schema.Choice(
760        source = nats_vocab,
761        title = _(u'Nationality'),
762        required = True,
763        )
764
765IPUTMEApplicantEdit[
766    'date_of_birth'].order =  ICustomUGApplicant['date_of_birth'].order
767IPUTMEApplicantEdit[
768    'email'].order =  ICustomUGApplicant['email'].order
769IPUTMEApplicantEdit[
770    'nationality'].order =  ICustomUGApplicant['nationality'].order
771
[9056]772class ICustomApplicantUpdateByRegNo(INigeriaApplicantUpdateByRegNo):
[8582]773    """Representation of an applicant.
774
775    Skip regular reg_number validation if reg_number is used for finding
776    the applicant object.
777    """
Note: See TracBrowser for help on using the repository browser.