source: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/applicants/interfaces.py @ 16276

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

Email addresses must be unique in IUO.

  • Property svn:keywords set to Id
File size: 23.3 KB
Line 
1# -*- coding: utf-8 -*-
2## $Id: interfaces.py 16276 2020-10-09 09:00:55Z 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
22from zope import schema
23from zope.component import getUtility
24from zope.catalog.interfaces import ICatalog
25from zc.sourcefactory.basic import BasicSourceFactory
26from waeup.kofa.applicants.interfaces import (
27    IApplicantBaseData,
28    AppCatCertificateSource, CertificateSource)
29from waeup.kofa.schoolgrades import ResultEntryField
30from waeup.kofa.university.vocabularies import StudyModeSource
31from waeup.kofa.interfaces import (
32    SimpleKofaVocabulary, academic_sessions_vocab, validate_email,
33    IKofaObject)
34from waeup.kofa.schema import FormattedDate, TextLineChoice, PhoneNumber
35from waeup.kofa.students.vocabularies import (
36    nats_vocab, GenderSource, StudyLevelSource)
37from waeup.kofa.applicants.interfaces import (
38    contextual_reg_num_source, IApplicantBaseData, IApplicantRefereeReport,
39    contextual_email_source, IApplicantRegisterUpdate)
40from waeup.kofa.refereeentries import RefereeEntryField
41from kofacustom.nigeria.applicants.interfaces import (
42    LGASource, high_qual, high_grade, exam_types, DisabilitiesSource,
43    programme_types_vocab, jambsubjects, validate_jamb_reg_number,
44    INigeriaUGApplicant, INigeriaPGApplicant,
45    INigeriaApplicantOnlinePayment,
46    INigeriaUGApplicantEdit, INigeriaPGApplicantEdit,
47    INigeriaApplicantUpdateByRegNo,
48    IPUTMEApplicantEdit,
49    )
50from kofacustom.iuokada.interfaces import MessageFactory as _
51from kofacustom.iuokada.payments.interfaces import ICustomOnlinePayment
52
53sponsors_vocab = SimpleKofaVocabulary(
54    (_('Bauchi Government'), 'bauchi'),
55    (_('Company'), 'company'),
56    (_('Federal Government of Nigeria'), 'federalgov'),
57    #(_('Dangote Group'), 'dangote'),
58    (_('Kano Government'), 'kano'),
59    (_('Parent/Guardian'), 'parent'),
60    (_('Rosula Organization'), 'rosula'),
61    (_('Self'), 'self'),
62    #(_('Social Impact Project'), 'social'),
63    )
64
65heard_about_types_vocab = SimpleKofaVocabulary(
66    (_('Facebook/Twitter/Other Social Media'), 'socmedia'),
67    (_('From a Friend'), 'friend'),
68    (_('Newspaper Advertisement'), 'newspaper'),
69    (_('Radio Advertisement'), 'radio'),
70    (_('Television Advertisement'), 'television'),
71    (_('SMS'), 'sms'),
72    )
73
74subtype_vocab = SimpleKofaVocabulary(
75    (_('UTME'), 'utme'),
76    (_('Direct Entry'), 'de'),
77    (_('Inter Uni Transfer'), 'transfer'),
78    )
79
80rating_vocab = SimpleKofaVocabulary(
81    (_('Excellent'), 'e'),
82    (_('Very good'), 'vg'),
83    (_('Good'), 'g'),
84    (_('Slightly above average'), 'saa'),
85    (_('Average'), 'a'),
86    (_('Below average'), 'ba'),
87    (_('Unable to assess'), 'unable'),
88    )
89
90
91overallpromise_vocab = SimpleKofaVocabulary(
92    (_('Very good (highest 10%)'), 'vg'),
93    (_('Above average (next 15%)'), 'aa'),
94    (_('Average (middle 20%)'), 'a'),
95    (_('Below average (middle 40%)'), 'ba'),
96    )
97
98DESTINATION_COST = {
99    'local': ('Local (Nigeria)', 15000.0, 1),
100    'overseas': ('Overseas', 25000.0, 2),
101    }
102
103class DestinationCostSource(BasicSourceFactory):
104    """A source that delivers continents and shipment costs.
105    """
106    def getValues(self):
107        sorted_items = sorted(DESTINATION_COST.items(),
108                              key=lambda element: element[1][2])
109        return [item[0] for item in sorted_items]
110
111    def getTitle(self, value):
112        return u"%s (₦ %s)" % (
113            DESTINATION_COST[value][0],
114            DESTINATION_COST[value][1])
115
116class TranscriptCertificateSource(CertificateSource):
117    """Include Department and Faculty in Title.
118    """
119    def getValues(self, context):
120        catalog = getUtility(ICatalog, name='certificates_catalog')
121        resultset = catalog.searchResults(code=(None, None))
122        resultlist = sorted(resultset, key=lambda
123            value: value.__parent__.__parent__.__parent__.code +
124            value.__parent__.__parent__.code +
125            value.code)
126        return resultlist
127
128    def getTitle(self, context, value):
129        """
130        """
131        try: title = "%s / %s / %s (%s)" % (
132            value.__parent__.__parent__.__parent__.title,
133            value.__parent__.__parent__.title,
134            value.title, value.code)
135        except AttributeError:
136            title = "NA / %s (%s)" % (value.title, value.code)
137        return title
138
139class ICustomUGApplicant(IApplicantBaseData):
140    """An undergraduate applicant.
141
142    This interface defines the least common multiple of all fields
143    in ug application forms. In customized forms, fields can be excluded by
144    adding them to the UG_OMIT* tuples.
145    """
146
147    email = TextLineChoice(
148        title = _(u'Email Address Test'),
149        required = False,
150        constraint=validate_email,
151        source = contextual_email_source,
152        )
153
154    subtype = schema.Choice(
155        title = _(u'Application Subtype'),
156        vocabulary = subtype_vocab,
157        required = False,
158        )
159    disabilities = schema.Choice(
160        title = _(u'Disability'),
161        source = DisabilitiesSource(),
162        required = False,
163        )
164    nationality = schema.Choice(
165        source = nats_vocab,
166        title = _(u'Nationality'),
167        required = False,
168        )
169    lga = schema.Choice(
170        source = LGASource(),
171        title = _(u'State/LGA (Nigerians only)'),
172        required = False,
173        )
174    sponsor = schema.Choice(
175        title = _(u'Sponsor'),
176        vocabulary = sponsors_vocab,
177        required = False,
178        )
179    heard_about = schema.Choice(
180        title = _(u'How did you hear about IUO?'),
181        vocabulary = heard_about_types_vocab,
182        required = False,
183        )
184    #perm_address = schema.Text(
185    #    title = _(u'Permanent Address'),
186    #    required = False,
187    #    )
188    parents_name = schema.TextLine(
189        title = _(u'Full Name'),
190        required = False,
191        readonly = False,
192        )
193    parents_email = schema.ASCIILine(
194        title = _(u'Email Address'),
195        required = False,
196        constraint=validate_email,
197        )
198    parents_phone = PhoneNumber(
199        title = _(u'Phone'),
200        required = False,
201        )
202    course1 = schema.Choice(
203        title = _(u'1st Choice Course of Study'),
204        source = AppCatCertificateSource(),
205        required = True,
206        )
207    course2 = schema.Choice(
208        title = _(u'2nd Choice Course of Study'),
209        source = AppCatCertificateSource(),
210        required = False,
211        )
212    programme_type = schema.Choice(
213        title = _(u'Programme Type'),
214        vocabulary = programme_types_vocab,
215        required = False,
216        )
217    fst_sit_fname = schema.TextLine(
218        title = _(u'Full Name'),
219        required = False,
220        readonly = False,
221        )
222    fst_sit_no = schema.TextLine(
223        title = _(u'Exam Number'),
224        required = False,
225        readonly = False,
226        )
227    fst_sit_date = FormattedDate(
228        title = _(u'Exam Date'),
229        required = False,
230        readonly = False,
231        show_year = True,
232        )
233    fst_sit_type = schema.Choice(
234        title = _(u'Exam Type'),
235        required = False,
236        readonly = False,
237        vocabulary = exam_types,
238        )
239    fst_sit_results = schema.List(
240        title = _(u'Exam Results'),
241        value_type = ResultEntryField(),
242        required = False,
243        readonly = False,
244        defaultFactory=list,
245        )
246    scd_sit_fname = schema.TextLine(
247        title = _(u'Full Name'),
248        required = False,
249        readonly = False,
250        )
251    scd_sit_no = schema.TextLine(
252        title = _(u'Exam Number'),
253        required = False,
254        readonly = False,
255        )
256    scd_sit_date = FormattedDate(
257        title = _(u'Exam Date'),
258        required = False,
259        readonly = False,
260        show_year = True,
261        )
262    scd_sit_type = schema.Choice(
263        title = _(u'Exam Type'),
264        required = False,
265        readonly = False,
266        vocabulary = exam_types,
267        )
268    scd_sit_results = schema.List(
269        title = _(u'Exam Results'),
270        value_type = ResultEntryField(),
271        required = False,
272        readonly = False,
273        defaultFactory=list,
274        )
275    hq_type = schema.Choice(
276        title = _(u'Qualification Obtained'),
277        required = False,
278        readonly = False,
279        vocabulary = high_qual,
280        )
281    hq_matric_no = schema.TextLine(
282        title = _(u'Former Matric Number'),
283        required = False,
284        readonly = False,
285        )
286    hq_degree = schema.Choice(
287        title = _(u'Class of Degree'),
288        required = False,
289        readonly = False,
290        vocabulary = high_grade,
291        )
292    hq_school = schema.TextLine(
293        title = _(u'Institution Attended'),
294        required = False,
295        readonly = False,
296        )
297    hq_session = schema.TextLine(
298        title = _(u'Years Attended'),
299        required = False,
300        readonly = False,
301        )
302    hq_disc = schema.TextLine(
303        title = _(u'Discipline'),
304        required = False,
305        readonly = False,
306        )
307    #jamb_subjects = schema.Text(
308    #    title = _(u'Subjects and Scores'),
309    #    required = False,
310    #    )
311    jamb_subjects_list = schema.List(
312        title = _(u'JAMB Subjects'),
313        required = False,
314        defaultFactory=list,
315        value_type = schema.Choice(
316            vocabulary = jambsubjects
317            #source = JAMBSubjectSource(),
318            ),
319        )
320    jamb_score = schema.Int(
321        title = _(u'Total JAMB Score'),
322        required = False,
323        )
324    #jamb_age = schema.Int(
325    #    title = _(u'Age (provided by JAMB)'),
326    #    required = False,
327    #    )
328    jamb_reg_number = schema.TextLine(
329        title = _(u'JAMB Registration Number'),
330        required = False,
331        constraint=validate_jamb_reg_number,
332        )
333    notice = schema.Text(
334        title = _(u'Notice'),
335        required = False,
336        )
337    screening_venue = schema.TextLine(
338        title = _(u'Screening Venue'),
339        required = False,
340        )
341    screening_date = schema.TextLine(
342        title = _(u'Screening Date'),
343        required = False,
344        )
345    screening_score = schema.Int(
346        title = _(u'Screening Score (%)'),
347        required = False,
348        )
349    aggregate = schema.Int(
350        title = _(u'Aggregate Score (%)'),
351        description = _(u'(average of relative JAMB and PUTME scores)'),
352        required = False,
353        )
354    result_uploaded = schema.Bool(
355        title = _(u'Result uploaded'),
356        default = False,
357        required = False,
358        )
359    student_id = schema.TextLine(
360        title = _(u'Student Id'),
361        required = False,
362        readonly = False,
363        )
364    course_admitted = schema.Choice(
365        title = _(u'Admitted Course of Study'),
366        source = CertificateSource(),
367        required = False,
368        )
369    locked = schema.Bool(
370        title = _(u'Form locked'),
371        default = False,
372        required = False,
373        )
374
375ICustomUGApplicant[
376    'subtype'].order =  ICustomUGApplicant['lga'].order
377ICustomUGApplicant[
378    'locked'].order =  ICustomUGApplicant['suspended'].order
379ICustomUGApplicant[
380    'result_uploaded'].order =  ICustomUGApplicant['suspended'].order
381
382class ICustomPGApplicant(INigeriaPGApplicant):
383    """A postgraduate applicant.
384
385    This interface defines the least common multiple of all fields
386    in pg application forms. In customized forms, fields can be excluded by
387    adding them to the PG_OMIT* tuples.
388    """
389
390    email = TextLineChoice(
391        title = _(u'Email Address Test'),
392        required = False,
393        constraint=validate_email,
394        source = contextual_email_source,
395        )
396
397    sponsor = schema.Choice(
398        title = _(u'Sponsor'),
399        vocabulary = sponsors_vocab,
400        required = False,
401        )
402
403    heard_about = schema.Choice(
404        title = _(u'How did you hear about IU?'),
405        vocabulary = heard_about_types_vocab,
406        required = False,
407        )
408
409    nysc_number = schema.Int(
410        title = _(u'Nysc Number'),
411        required = False,
412        readonly = False,
413        )
414
415    referees = schema.List(
416        title = _(u'Referees'),
417        value_type = RefereeEntryField(),
418        required = False,
419        defaultFactory=list,
420        )
421
422ICustomPGApplicant[
423    'referees'].order =  INigeriaPGApplicant['emp2_reason'].order
424ICustomPGApplicant[
425    'sponsor'].order =  ICustomPGApplicant['lga'].order
426ICustomPGApplicant[
427    'heard_about'].order =  ICustomPGApplicant['lga'].order
428ICustomPGApplicant[
429    'sponsor'].order =  ICustomPGApplicant['lga'].order
430ICustomPGApplicant[
431    'lga'].order =  ICustomPGApplicant['nationality'].order
432ICustomPGApplicant[
433    'nysc_number'].order =  ICustomPGApplicant['nysc_year'].order
434
435class ITranscriptApplicant(IKofaObject):
436    """A transcript applicant.
437    """
438
439    suspended = schema.Bool(
440        title = _(u'Account suspended'),
441        default = False,
442        required = False,
443        )
444
445    locked = schema.Bool(
446        title = _(u'Form locked'),
447        default = False,
448        required = False,
449        )
450
451    applicant_id = schema.TextLine(
452        title = _(u'Transcript Application Id'),
453        required = False,
454        readonly = False,
455        )
456
457    matric_number = schema.TextLine(
458        title = _(u'Matriculation Number'),
459        readonly = False,
460        required = True,
461        )
462
463    firstname = schema.TextLine(
464        title = _(u'First Name'),
465        required = True,
466        )
467
468    middlename = schema.TextLine(
469        title = _(u'Middle Name'),
470        required = False,
471        )
472
473    lastname = schema.TextLine(
474        title = _(u'Last Name (Surname)'),
475        required = True,
476        )
477
478    #date_of_birth = FormattedDate(
479    #    title = _(u'Date of Birth'),
480    #    required = False,
481    #    #date_format = u'%d/%m/%Y', # Use grok-instance-wide default
482    #    show_year = True,
483    #    )
484
485    sex = schema.Choice(
486        title = _(u'Gender'),
487        source = GenderSource(),
488        required = True,
489        )
490
491    #nationality = schema.Choice(
492    #    vocabulary = nats_vocab,
493    #    title = _(u'Nationality'),
494    #    required = False,
495    #    )
496
497    email = schema.ASCIILine(
498        title = _(u'Email Address'),
499        required = True,
500        constraint=validate_email,
501        )
502
503    #phone = PhoneNumber(
504    #    title = _(u'Phone'),
505    #    description = u'',
506    #    required = False,
507    #    )
508
509    #perm_address = schema.Text(
510    #    title = _(u'Current Local Address'),
511    #    required = False,
512    #    readonly = False,
513    #    )
514
515    dispatch_address = schema.Text(
516        title = _(u'Dispatch Addresses'),
517        description = u'Addresses to which transcripts should be posted. '
518                       'Addresses must involve same courier charges.',
519        required = False,
520        readonly = False,
521        )
522
523    charge = schema.Choice(
524        title = _(u'Courier Charge'),
525        source = DestinationCostSource(),
526        required = True,
527        )
528
529    #entry_mode = schema.Choice(
530    #    title = _(u'Entry Mode'),
531    #    source = StudyModeSource(),
532    #    required = False,
533    #    readonly = False,
534    #    )
535
536    #entry_session = schema.Choice(
537    #    title = _(u'Entry Session'),
538    #    source = academic_sessions_vocab,
539    #    required = False,
540    #    readonly = False,
541    #    )
542
543    end_session = schema.Choice(
544        title = _(u'Academic Session of Graduation'),
545        source = academic_sessions_vocab,
546        required = False,
547        readonly = False,
548        )
549
550    course_studied = schema.Choice(
551        title = _(u'Course of Study'),
552        source = TranscriptCertificateSource(),
553        description = u'Faculty / Department / Course',
554        required = False,
555        readonly = False,
556        )
557
558    #course_changed = schema.Choice(
559    #    title = _(u'Change of Study Course'),
560    #    description = u'If yes, select previous course of study.',
561    #    source = CertificateSource(),
562    #    readonly = False,
563    #    required = False,
564    #    )
565
566    #change_level = schema.Choice(
567    #    title = _(u'Change Level'),
568    #    description = u'If yes, select level at which you changed course of study.',
569    #    source = StudyLevelSource(),
570    #    required = False,
571    #    readonly = False,
572    #    )
573
574    no_copies = schema.Choice(
575        title = _(u'Number of Copies'),
576        description = u'Must correspond with the number of dispatch addresses above.',
577        values=[1, 2, 3, 4],
578        required = False,
579        readonly = False,
580        default = 1,
581        )
582
583class ICustomApplicant(ICustomUGApplicant, ICustomPGApplicant,
584    ITranscriptApplicant):
585    """An interface for both types of applicants.
586
587    Attention: The ICustomPGApplicant field seetings will be overwritten
588    by ICustomPGApplicant field settings. If a field is defined
589    in both interfaces zope.schema validates only against the
590    constraints in ICustomUGApplicant. This does not affect the forms
591    since they are build on either ICustomUGApplicant or ICustomPGApplicant.
592    """
593
594    def writeLogMessage(view, comment):
595        """Adds an INFO message to the log file
596        """
597
598    def createStudent():
599        """Create a student object from applicant data
600        and copy applicant object.
601        """
602
603class ICustomUGApplicantEdit(ICustomUGApplicant):
604    """An undergraduate applicant interface for edit forms.
605
606    Here we can repeat the fields from base data and set the
607    `required` and `readonly` attributes to True to further restrict
608    the data access. Or we can allow only certain certificates to be
609    selected by choosing the appropriate source.
610
611    We cannot omit fields here. This has to be done in the
612    respective form page.
613    """
614
615    phone = PhoneNumber(
616        title = _(u'Phone'),
617        description = u'',
618        required = True,
619        )
620    email = TextLineChoice(
621        title = _(u'Email Address Test'),
622        required = False,
623        constraint=validate_email,
624        source = contextual_email_source,
625        )
626    date_of_birth = FormattedDate(
627        title = _(u'Date of Birth'),
628        required = True,
629        show_year = True,
630        )
631
632ICustomUGApplicantEdit[
633    'date_of_birth'].order = ICustomUGApplicant['date_of_birth'].order
634ICustomUGApplicantEdit[
635    'email'].order = ICustomUGApplicant['email'].order
636ICustomUGApplicantEdit[
637    'phone'].order =  ICustomUGApplicantEdit['email'].order
638
639class ICustomPGApplicantEdit(ICustomPGApplicant):
640    """A postgraduate applicant interface for editing.
641
642    Here we can repeat the fields from base data and set the
643    `required` and `readonly` attributes to True to further restrict
644    the data access. Or we can allow only certain certificates to be
645    selected by choosing the appropriate source.
646
647    We cannot omit fields here. This has to be done in the
648    respective form page.
649    """
650
651    phone = PhoneNumber(
652        title = _(u'Phone'),
653        description = u'',
654        required = True,
655        )
656    email = TextLineChoice(
657        title = _(u'Email Address Test'),
658        required = False,
659        constraint=validate_email,
660        source = contextual_email_source,
661        )
662    date_of_birth = FormattedDate(
663        title = _(u'Date of Birth'),
664        required = True,
665        show_year = True,
666        )
667
668ICustomPGApplicantEdit[
669    'date_of_birth'].order = ICustomPGApplicant['date_of_birth'].order
670ICustomPGApplicantEdit[
671    'email'].order = ICustomPGApplicant['email'].order
672ICustomPGApplicantEdit[
673    'phone'].order =  ICustomPGApplicantEdit['email'].order
674
675class ICustomApplicantRegisterUpdate(IApplicantRegisterUpdate):
676    """This is a representation of an applicant for first-time registration.
677    This interface is used when applicants use the registration page to
678    update their records.
679    """
680
681    email = TextLineChoice(
682        title = _(u'Email Address Test'),
683        required = False,
684        constraint=validate_email,
685        source = contextual_email_source,
686        )
687
688class ICustomApplicantOnlinePayment(INigeriaApplicantOnlinePayment):
689    """An applicant payment via payment gateways.
690
691    """
692
693class IPUTMEApplicantEdit(IPUTMEApplicantEdit):
694    """An undergraduate applicant interface for editing.
695
696    Here we can repeat the fields from base data and set the
697    `required` and `readonly` attributes to True to further restrict
698    the data access. Or we can allow only certain certificates to be
699    selected by choosing the appropriate source.
700
701    We cannot omit fields here. This has to be done in the
702    respective form page.
703    """
704
705class ICustomApplicantUpdateByRegNo(INigeriaApplicantUpdateByRegNo):
706    """Representation of an applicant.
707
708    Skip regular reg_number validation if reg_number is used for finding
709    the applicant object.
710    """
711
712class ICustomApplicantRefereeReport(IApplicantRefereeReport):
713    """A referee report.
714    """
715
716    duration = schema.Text(
717        title = _(u'How long and in what capacity have you known the candidate?'),
718        required = False,
719        )
720
721    itellectual = schema.Choice(
722        title = _(u'Intellectual Capacity'),
723        required = False,
724        readonly = False,
725        vocabulary = rating_vocab,
726        )
727
728    persistent = schema.Choice(
729        title = _(u'Capacity for Persistent and Independent Academic Study'),
730        required = False,
731        readonly = False,
732        vocabulary = rating_vocab,
733        )
734
735    imaginative = schema.Choice(
736        title = _(u'Ability for Imaginative Thought'),
737        required = False,
738        readonly = False,
739        vocabulary = rating_vocab,
740        )
741
742    productive = schema.Choice(
743        title = _(u'Promise of Productive Scholarship'),
744        required = False,
745        readonly = False,
746        vocabulary = rating_vocab,
747        )
748
749    previous = schema.Choice(
750        title = _(u'Quality of Previous Work'),
751        required = False,
752        readonly = False,
753        vocabulary = rating_vocab,
754        )
755
756    expression = schema.Choice(
757        title = _(u'Oral and Written Expression in English'),
758        required = False,
759        readonly = False,
760        vocabulary = rating_vocab,
761        )
762
763    personality = schema.Text(
764        title = _(u'Please comment on the candidate\'s personality '
765            'with particular reference to his/her moral character, emotional '
766            'and physical stabilty'),
767        required = False,
768        )
769
770    promise = schema.Choice(
771        title = _(u'Candidate\'s overall promise'),
772        required = False,
773        readonly = False,
774        vocabulary = overallpromise_vocab,
775        )
776
777    report = schema.Text(
778        title = _(u'Any other relevant information which would help '
779            'in determining the candidate\'s suitability?'),
780        required = False,
781        )
782
783    objection = schema.Text(
784        title = _(u'Have you any objection to the contents of this '
785            'evaluation being disclosed to any award-given body if '
786            'the need arises?'),
787        required = False,
788        )
Note: See TracBrowser for help on using the repository browser.