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

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

Make dispatch_address a required field.

  • Property svn:keywords set to Id
File size: 22.1 KB
RevLine 
[13814]1# -*- coding: utf-8 -*-
[7853]2## $Id: interfaces.py 16307 2020-11-10 09:56:37Z 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',
[16078]369        required = False,
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
[14140]425class ICustomUGApplicant(IApplicantBaseData, IBankAccount):
[8012]426    """An undergraduate applicant.
427
[8519]428    This interface defines the least common multiple of all fields
429    in ug application forms. In customized forms, fields can be excluded by
430    adding them to the UG_OMIT* tuples.
[8012]431    """
432
[15490]433    disabilities = schema.Choice(
434        title = _(u'Disabilities'),
435        source = DisabilitiesSource(),
436        required = False,
437        )
[14140]438    nationality = schema.Choice(
439        source = nats_vocab,
440        title = _(u'Nationality'),
441        required = False,
442        )
443    lga = schema.Choice(
444        source = LGASource(),
445        title = _(u'State/LGA (Nigerians only)'),
446        required = False,
447        )
448    #perm_address = schema.Text(
449    #    title = _(u'Permanent Address'),
450    #    required = False,
451    #    )
452    course1 = schema.Choice(
453        title = _(u'1st Choice Course of Study'),
454        source = AppCatCertificateSource(),
455        required = True,
456        )
457    course2 = schema.Choice(
458        title = _(u'2nd Choice Course of Study'),
459        source = AppCatCertificateSource(),
460        required = False,
461        )
462
463    programme_type = schema.Choice(
464        title = _(u'Programme Type'),
465        vocabulary = programme_types_vocab,
466        required = False,
467        )
468
469    hq_type = schema.Choice(
470        title = _(u'Qualification Obtained'),
471        required = False,
472        readonly = False,
473        vocabulary = high_qual,
474        )
475    hq_matric_no = schema.TextLine(
476        title = _(u'Former Matric Number'),
477        required = False,
478        readonly = False,
479        )
480    hq_degree = schema.Choice(
481        title = _(u'Class of Degree'),
482        required = False,
483        readonly = False,
484        vocabulary = high_grade,
485        )
486    hq_school = schema.TextLine(
487        title = _(u'Institution Attended'),
488        required = False,
489        readonly = False,
490        )
491    hq_session = schema.TextLine(
492        title = _(u'Years Attended'),
493        required = False,
494        readonly = False,
495        )
496    hq_disc = schema.TextLine(
497        title = _(u'Discipline'),
498        required = False,
499        readonly = False,
500        )
[14141]501    fst_sit_fname = schema.TextLine(
502        title = _(u'Full Name'),
503        required = False,
504        readonly = False,
505        )
506    fst_sit_no = schema.TextLine(
507        title = _(u'Exam Number'),
508        required = False,
509        readonly = False,
510        )
511    fst_sit_date = FormattedDate(
512        title = _(u'Exam Date'),
513        required = False,
514        readonly = False,
515        show_year = True,
516        )
517    fst_sit_type = schema.Choice(
518        title = _(u'Exam Type'),
519        required = False,
520        readonly = False,
521        vocabulary = exam_types,
522        )
523    fst_sit_results = schema.List(
524        title = _(u'Exam Results'),
525        value_type = ResultEntryField(),
526        required = False,
527        readonly = False,
528        defaultFactory=list,
529        )
530    scd_sit_fname = schema.TextLine(
531        title = _(u'Full Name'),
532        required = False,
533        readonly = False,
534        )
535    scd_sit_no = schema.TextLine(
536        title = _(u'Exam Number'),
537        required = False,
538        readonly = False,
539        )
540    scd_sit_date = FormattedDate(
541        title = _(u'Exam Date'),
542        required = False,
543        readonly = False,
544        show_year = True,
545        )
546    scd_sit_type = schema.Choice(
547        title = _(u'Exam Type'),
548        required = False,
549        readonly = False,
550        vocabulary = exam_types,
551        )
552    scd_sit_results = schema.List(
553        title = _(u'Exam Results'),
554        value_type = ResultEntryField(),
555        required = False,
556        readonly = False,
557        defaultFactory=list,
558        )
[14140]559    jamb_subjects = schema.Text(
560        title = _(u'Subjects and Scores'),
561        required = False,
562        )
563    jamb_subjects_list = schema.List(
564        title = _(u'JAMB Subjects'),
565        required = False,
566        defaultFactory=list,
567        value_type = schema.Choice(
568            vocabulary = jambsubjects
569            #source = JAMBSubjectSource(),
570            ),
571        )
572    jamb_score = schema.Int(
573        title = _(u'Total JAMB Score'),
574        required = False,
575        )
576    #jamb_age = schema.Int(
577    #    title = _(u'Age (provided by JAMB)'),
578    #    required = False,
579    #    )
580    jamb_reg_number = schema.TextLine(
581        title = _(u'JAMB Registration Number'),
582        required = False,
583        )
584    notice = schema.Text(
585        title = _(u'Notice'),
586        required = False,
587        )
588    screening_venue = schema.TextLine(
589        title = _(u'Screening Venue'),
590        required = False,
591        )
592    screening_date = schema.TextLine(
593        title = _(u'Screening Date'),
594        required = False,
595        )
596    screening_score = schema.Int(
597        title = _(u'Screening Score (%)'),
598        required = False,
599        )
600    aggregate = schema.Int(
601        title = _(u'Aggregate Score (%)'),
602        description = _(u'(average of relative JAMB and PUTME scores)'),
603        required = False,
604        )
605    result_uploaded = schema.Bool(
606        title = _(u'Result uploaded'),
607        default = False,
608        required = False,
609        )
610    student_id = schema.TextLine(
611        title = _(u'Student Id'),
612        required = False,
613        readonly = False,
614        )
615    course_admitted = schema.Choice(
616        title = _(u'Admitted Course of Study'),
617        source = CertificateSource(),
618        required = False,
619        )
620    locked = schema.Bool(
621        title = _(u'Form locked'),
622        default = False,
623        required = False,
624        )
625
626ICustomUGApplicant[
627    'locked'].order =  IApplicantBaseData['suspended'].order
628ICustomUGApplicant[
629    'result_uploaded'].order =  ICustomUGApplicant['suspended'].order
630
[8928]631class ICustomPGApplicant(INigeriaPGApplicant):
[7853]632    """A postgraduate applicant.
633
[8519]634    This interface defines the least common multiple of all fields
635    in pg application forms. In customized forms, fields can be excluded by
636    adding them to the PG_OMIT* tuples.
[7866]637    """
638
[14106]639    referees = schema.List(
640        title = _(u'Referees'),
641        value_type = RefereeEntryField(),
642        required = False,
643        defaultFactory=list,
644        )
[8012]645
[14106]646ICustomPGApplicant[
647    'referees'].order =  INigeriaPGApplicant['emp2_reason'].order
648
[13814]649class ICustomApplicant(ICustomUGApplicant, ICustomPGApplicant,
[16078]650    IUnibenRegistration, ITranscriptApplicant):
[8012]651    """An interface for both types of applicants.
652
[8928]653    Attention: The ICustomPGApplicant field seetings will be overwritten
654    by ICustomPGApplicant field settings. If a field is defined
[8727]655    in both interfaces zope.schema validates only against the
[8928]656    constraints in ICustomUGApplicant. This does not affect the forms
657    since they are build on either ICustomUGApplicant or ICustomPGApplicant.
[8012]658    """
659
[8743]660    def writeLogMessage(view, comment):
[8053]661        """Adds an INFO message to the log file
662        """
663
664    def createStudent():
[8668]665        """Create a student object from applicant data
[8053]666        and copy applicant object.
667        """
668
[14212]669class ICustomUGApplicantEdit(ICustomUGApplicant):
[8727]670    """An undergraduate applicant interface for edit forms.
[8012]671
672    Here we can repeat the fields from base data and set the
673    `required` and `readonly` attributes to True to further restrict
674    the data access. Or we can allow only certain certificates to be
675    selected by choosing the appropriate source.
676
677    We cannot omit fields here. This has to be done in the
678    respective form page.
679    """
680
[14212]681    email = schema.ASCIILine(
682        title = _(u'Email Address'),
683        required = True,
684        constraint=validate_email,
685        )
686    date_of_birth = FormattedDate(
687        title = _(u'Date of Birth'),
688        required = True,
689        show_year = True,
690        )
691
692ICustomUGApplicantEdit[
693    'date_of_birth'].order = ICustomUGApplicant['date_of_birth'].order
694ICustomUGApplicantEdit[
695    'email'].order = ICustomUGApplicant['email'].order
696
[9056]697class ICustomPGApplicantEdit(INigeriaPGApplicantEdit):
[7866]698    """A postgraduate applicant interface for editing.
699
700    Here we can repeat the fields from base data and set the
701    `required` and `readonly` attributes to True to further restrict
702    the data access. Or we can allow only certain certificates to be
703    selected by choosing the appropriate source.
704
705    We cannot omit fields here. This has to be done in the
706    respective form page.
[8017]707    """
[8454]708
[14106]709    referees = schema.List(
710        title = _(u'Referees'),
711        value_type = RefereeEntryField(),
712        required = False,
713        defaultFactory=list,
714        )
[13814]715
[14106]716ICustomPGApplicantEdit[
717    'referees'].order =  INigeriaPGApplicantEdit['emp2_reason'].order
718
[8928]719class ICustomApplicantOnlinePayment(INigeriaApplicantOnlinePayment):
[8247]720    """An applicant payment via payment gateways.
721
722    """
[8530]723
[14153]724class IPUTMEApplicantEdit(ICustomUGApplicant):
[8530]725    """An undergraduate applicant interface for editing.
726
727    Here we can repeat the fields from base data and set the
728    `required` and `readonly` attributes to True to further restrict
729    the data access. Or we can allow only certain certificates to be
730    selected by choosing the appropriate source.
731
732    We cannot omit fields here. This has to be done in the
733    respective form page.
734    """
735
[14153]736    email = schema.ASCIILine(
737        title = _(u'Email Address'),
738        required = True,
739        constraint=validate_email,
740        )
741    date_of_birth = FormattedDate(
742        title = _(u'Date of Birth'),
743        required = True,
744        show_year = True,
745        )
746    nationality = schema.Choice(
747        source = nats_vocab,
748        title = _(u'Nationality'),
749        required = True,
750        )
751
752IPUTMEApplicantEdit[
753    'date_of_birth'].order =  ICustomUGApplicant['date_of_birth'].order
754IPUTMEApplicantEdit[
755    'email'].order =  ICustomUGApplicant['email'].order
756IPUTMEApplicantEdit[
757    'nationality'].order =  ICustomUGApplicant['nationality'].order
758
[9056]759class ICustomApplicantUpdateByRegNo(INigeriaApplicantUpdateByRegNo):
[8582]760    """Representation of an applicant.
761
762    Skip regular reg_number validation if reg_number is used for finding
763    the applicant object.
764    """
Note: See TracBrowser for help on using the repository browser.