source: main/kofacustom.edocons/trunk/src/kofacustom/edocons/applicants/interfaces.py @ 17513

Last change on this file since 17513 was 17488, checked in by Henrik Bettermann, 18 months ago

Remove required flag from JAMB fields.

  • Property svn:keywords set to Id
File size: 21.7 KB
Line 
1# -*- coding: utf-8 -*-
2## $Id: interfaces.py 17488 2023-07-14 08:51:19Z 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 datetime import datetime
23from zope import schema
24from zope.interface import invariant, Invalid
25from zope.component import getUtility
26from zope.catalog.interfaces import ICatalog
27from zc.sourcefactory.basic import BasicSourceFactory
28from waeup.kofa.university.vocabularies import StudyModeSource
29from waeup.kofa.applicants.interfaces import (
30    IApplicantBaseData,
31    AppCatCertificateSource, CertificateSource)
32from waeup.kofa.schoolgrades import ResultEntryField
33from waeup.kofa.interfaces import (
34    SimpleKofaVocabulary, academic_sessions_vocab, validate_email,
35    IKofaObject, MonthSource)
36from waeup.kofa.schema import FormattedDate, TextLineChoice, PhoneNumber
37from waeup.kofa.students.vocabularies import nats_vocab, GenderSource
38from waeup.kofa.applicants.interfaces import (
39    contextual_reg_num_source,
40    year_range,
41    IApplicantBaseData)
42from kofacustom.nigeria.applicants.interfaces import (
43    LGASource, high_qual, high_grade, exam_types,
44    jambsubjects,
45    INigeriaUGApplicant, INigeriaPGApplicant,
46    INigeriaApplicantOnlinePayment,
47    INigeriaUGApplicantEdit, INigeriaPGApplicantEdit,
48    INigeriaApplicantUpdateByRegNo,
49    IPUTMEApplicantEdit,
50    )
51from kofacustom.nigeria.interfaces import (
52    LGASource, DisabilitiesSource,
53    high_qual, high_grade, exam_types, validate_jamb_reg_number)
54
55from kofacustom.edocons.interfaces import MessageFactory as _
56from kofacustom.edocons.payments.interfaces import ICustomOnlinePayment
57
58def entry_year_range():
59    curr_year = datetime.now().year
60    return range(curr_year - 50, curr_year)
61
62programme_types_vocab = SimpleKofaVocabulary(
63    (_('Post UTME'), 'putme'),
64    (_('Post DE'), 'pude'),
65    (_('Admission Screening Exercise'), 'ase'),
66    (_('not applicable'), 'na'),
67    )
68
69DESTINATION_COST = {
70    #'none': ('To the moon', 1000000000.0, 1),
71    'australia': ('Australia / India', 62500.0, 1),
72    'china': ('Arab Emirate / China', 62400.0, 2),
73    'france': ('France / Germany / Netherland / Norway / Sweden', 45300.0, 3),
74    'canada': ('Canada / USA', 56600.0, 4),
75    'finland': ('Finland / Jamaica', 69600.0, 5),
76    'israel': ('Israel', 52000, 6),
77    'turkey': ('Turkey', 57000.0, 7),
78    'uk': ('UK / Ireland', 43000.0, 8),
79    'ghana': ('Ghana / South Africa / Saudi Arabia',  57200.0, 9),
80    'beninrep': ('Republic of Benin', 48600.0, 10),
81    'north': ('Nigeria North', 23000.0, 11),
82    'south': ('Nigeria South East / South / South West', 20100.0, 12),
83    'abuja': ('Abuja', 20400.0, 13),
84    'lokoja': ('Lokoja', 23000.0, 14),
85    'auchi': ('Auchi / Epkoma / Usen / Irrua / Ekhiadolo / Uromi', 19500, 15),
86    'benincity': ('Benin City', 18200, 16),
87    }
88
89class DestinationCostSource(BasicSourceFactory):
90    """A source that delivers continents and shipment costs.
91    """
92    def getValues(self):
93        sorted_items = sorted(DESTINATION_COST.items(),
94                              key=lambda element: element[1][2])
95        return [item[0] for item in sorted_items]
96
97    def getToken(self, value):
98        return value
99
100    def getTitle(self, value):
101        return u"%s (₦ %s)" % (
102            DESTINATION_COST[value][0],
103            DESTINATION_COST[value][1])
104
105class OrderSource(BasicSourceFactory):
106    """
107    """
108    def getValues(self):
109        return ['c',]
110
111    def getToken(self, value):
112        return value
113
114    def getTitle(self, value):
115        #if value == 'o':
116        #    return _('Student Transcript')
117        if value == 'c':
118            return _('Certified Transcript')
119
120class TranscriptCertificateSource(CertificateSource):
121    """Include Department and Faculty in Title.
122    """
123    def getValues(self, context):
124        catalog = getUtility(ICatalog, name='certificates_catalog')
125        resultset = catalog.searchResults(code=(None, None))
126        resultlist = sorted(resultset, key=lambda
127            value: value.__parent__.__parent__.__parent__.code +
128            value.__parent__.__parent__.code +
129            value.code)
130        return resultlist
131
132    def getTitle(self, context, value):
133        """
134        """
135        try: title = "%s / %s / %s (%s)" % (
136            value.__parent__.__parent__.__parent__.title,
137            value.__parent__.__parent__.title,
138            value.title, value.code)
139        except AttributeError:
140            title = "NA / %s (%s)" % (value.title, value.code)
141        return title
142
143class ICustomUGApplicant(INigeriaUGApplicant):
144    """An undergraduate applicant.
145    """
146
147    disabilities = schema.Choice(
148        title = _(u'Disability'),
149        source = DisabilitiesSource(),
150        required = False,
151        )
152    nationality = schema.Choice(
153        source = nats_vocab,
154        title = _(u'Nationality'),
155        required = False,
156        )
157    lga = schema.Choice(
158        source = LGASource(),
159        title = _(u'State/LGA (Nigerians only)'),
160        required = True,
161        )
162    perm_address = schema.Text(
163        title = _(u'Permanent Address'),
164        required = False,
165        )
166
167    next_kin_name = schema.TextLine(
168        title = _(u'Next of Kin Name'),
169        required = False,
170        readonly = False,
171        )
172
173    next_kin_relation = schema.TextLine(
174        title = _(u'Next of Kin Relationship'),
175        required = False,
176        readonly = False,
177        )
178
179    next_kin_address = schema.Text(
180        title = _(u'Next of Kin Address'),
181        required = False,
182        readonly = False,
183        )
184
185    next_kin_phone = PhoneNumber(
186        title = _(u'Next of Kin Phone'),
187        required = False,
188        readonly = False,
189        )
190
191    course1 = schema.Choice(
192        title = _(u'1st Choice Course of Study'),
193        source = AppCatCertificateSource(),
194        required = True,
195        )
196    course2 = schema.Choice(
197        title = _(u'2nd Choice Course of Study'),
198        source = AppCatCertificateSource(),
199        required = False,
200        )
201
202    fst_sit_fname = schema.TextLine(
203        title = _(u'Full Name'),
204        required = False,
205        readonly = False,
206        )
207
208    fst_sit_no = schema.TextLine(
209        title = _(u'Exam Number'),
210        required = False,
211        readonly = False,
212        )
213
214    fst_sit_date = FormattedDate(
215        title = _(u'Exam Date'),
216        required = False,
217        readonly = False,
218        show_year = True,
219        )
220
221    fst_sit_type = schema.Choice(
222        title = _(u'Exam Type'),
223        required = False,
224        readonly = False,
225        vocabulary = exam_types,
226        )
227
228    fst_sit_results = schema.List(
229        title = _(u'Exam Results'),
230        value_type = ResultEntryField(),
231        required = False,
232        readonly = False,
233        defaultFactory=list,
234        )
235
236    scd_sit_fname = schema.TextLine(
237        title = _(u'Full Name'),
238        required = False,
239        readonly = False,
240        )
241
242    scd_sit_no = schema.TextLine(
243        title = _(u'Exam Number'),
244        required = False,
245        readonly = False,
246        )
247
248    scd_sit_date = FormattedDate(
249        title = _(u'Exam Date'),
250        required = False,
251        readonly = False,
252        show_year = True,
253        )
254
255    scd_sit_type = schema.Choice(
256        title = _(u'Exam Type'),
257        required = False,
258        readonly = False,
259        vocabulary = exam_types,
260        )
261
262    scd_sit_results = schema.List(
263        title = _(u'Exam Results'),
264        value_type = ResultEntryField(),
265        required = False,
266        readonly = False,
267        defaultFactory=list,
268        )
269
270    programme_type = schema.Choice(
271        title = _(u'Programme Type'),
272        vocabulary = programme_types_vocab,
273        required = False,
274        )
275
276    hq_type = schema.Choice(
277        title = _(u'Qualification Obtained'),
278        required = False,
279        readonly = False,
280        vocabulary = high_qual,
281        )
282    hq_matric_no = schema.TextLine(
283        title = _(u'Former Matric Number'),
284        required = False,
285        readonly = False,
286        )
287    hq_degree = schema.Choice(
288        title = _(u'Class of Degree'),
289        required = False,
290        readonly = False,
291        vocabulary = high_grade,
292        )
293    hq_school = schema.TextLine(
294        title = _(u'Institution Attended'),
295        required = False,
296        readonly = False,
297        )
298    hq_session = schema.TextLine(
299        title = _(u'Years Attended'),
300        required = False,
301        readonly = False,
302        )
303    hq_disc = schema.TextLine(
304        title = _(u'Discipline'),
305        required = False,
306        readonly = False,
307        )
308    jamb_reg_number = schema.TextLine(
309        title = _(u'JAMB Registration Number'),
310        required = False,
311        constraint=validate_jamb_reg_number,
312        )
313    jamb_subjects = schema.Text(
314        title = _(u'Subjects and Scores'),
315        required = False,
316        )
317    jamb_subjects_list = schema.List(
318        title = _(u'JAMB Subjects'),
319        required = False,
320        defaultFactory=list,
321        value_type = schema.Choice(
322            vocabulary = jambsubjects
323            #source = JAMBSubjectSource(),
324            ),
325        )
326    jamb_score = schema.Int(
327        title = _(u'Total JAMB Score'),
328        required = False,
329        )
330    #jamb_age = schema.Int(
331    #    title = _(u'Age (provided by JAMB)'),
332    #    required = False,
333    #    )
334    cbt_score = schema.Int(
335        title = _(u'CBT Score'),
336        required = False,
337        )
338    cbt_venue = schema.TextLine(
339        title = _(u'CBT Venue'),
340        required = False,
341        )
342    cbt_date = FormattedDate(
343        title = _(u'CBT Date'),
344        required = False,
345        )
346    notice = schema.Text(
347        title = _(u'Notice'),
348        required = False,
349        )
350    screening_venue = schema.TextLine(
351        title = _(u'Screening Venue'),
352        required = False,
353        )
354    screening_date = schema.TextLine(
355        title = _(u'Screening Date'),
356        required = False,
357        )
358    screening_score = schema.Int(
359        title = _(u'Screening Score (%)'),
360        required = False,
361        )
362    aggregate = schema.Int(
363        title = _(u'Aggregate Score (%)'),
364        description = _(u'(average of relative JAMB and PUTME scores)'),
365        required = False,
366        )
367    result_uploaded = schema.Bool(
368        title = _(u'Result uploaded'),
369        default = False,
370        required = False,
371        )
372    student_id = schema.TextLine(
373        title = _(u'Student Id'),
374        required = False,
375        readonly = False,
376        )
377    course_admitted = schema.Choice(
378        title = _(u'Admitted Course of Study'),
379        source = CertificateSource(),
380        required = False,
381        )
382    locked = schema.Bool(
383        title = _(u'Form locked'),
384        default = False,
385        required = False,
386        )
387
388class ICustomPGApplicant(INigeriaPGApplicant):
389    """A postgraduate applicant.
390
391    This interface defines the least common multiple of all fields
392    in pg application forms. In customized forms, fields can be excluded by
393    adding them to the PG_OMIT* tuples.
394    """
395
396class ITranscriptApplicant(IKofaObject):
397    """A transcript applicant.
398    """
399
400    suspended = schema.Bool(
401        title = _(u'Account suspended'),
402        default = False,
403        required = False,
404        )
405
406    locked = schema.Bool(
407        title = _(u'Form locked'),
408        default = False,
409        required = False,
410        )
411
412    applicant_id = schema.TextLine(
413        title = _(u'Transcript Application Id'),
414        required = False,
415        readonly = False,
416        )
417
418    student_id = schema.TextLine(
419        title = _(u'Kofa Student Id'),
420        required = False,
421        readonly = False,
422        )
423
424    matric_number = schema.TextLine(
425        title = _(u'Matriculation Number'),
426        readonly = False,
427        required = False,
428        )
429
430    firstname = schema.TextLine(
431        title = _(u'First Name in School'),
432        required = True,
433        )
434
435    middlename = schema.TextLine(
436        title = _(u'Middle Name in School'),
437        required = False,
438        )
439
440    lastname = schema.TextLine(
441        title = _(u'Surname in School'),
442        required = True,
443        )
444
445    date_of_birth = FormattedDate(
446        title = _(u'Date of Birth'),
447        required = False,
448        #date_format = u'%d/%m/%Y', # Use grok-instance-wide default
449        show_year = True,
450        )
451
452    sex = schema.Choice(
453        title = _(u'Gender'),
454        source = GenderSource(),
455        required = True,
456        )
457
458    nationality = schema.Choice(
459        vocabulary = nats_vocab,
460        title = _(u'Nationality'),
461        required = False,
462        )
463
464    email = schema.ASCIILine(
465        title = _(u'Email Address'),
466        required = True,
467        constraint=validate_email,
468        )
469
470    phone = PhoneNumber(
471        title = _(u'Phone'),
472        description = u'',
473        required = False,
474        )
475
476    #perm_address = schema.Text(
477    #    title = _(u'Current Local Address'),
478    #    required = False,
479    #    readonly = False,
480    #    )
481
482    collected = schema.Bool(
483        title = _(u'Have you collected transcript before?'),
484        default = False,
485        required = False,
486        )
487
488    entry_year = schema.Choice(
489        title = _(u'Year of Entrance'),
490        required = False,
491        values = entry_year_range(),
492        readonly = False,
493        )
494
495    entry_month = schema.Choice(
496        title = _(u'Month of Entry'),
497        source = MonthSource(),
498        required = False,
499        )
500
501    end_year = schema.Choice(
502        title = _(u'Year of Graduation'),
503        required = False,
504        values = entry_year_range(),
505        readonly = False,
506        )
507
508    end_month = schema.Choice(
509        title = _(u'Month of Graduation'),
510        source = MonthSource(),
511        required = False,
512        )
513
514    entry_mode = schema.Choice(
515        title = _(u'Course of Study'),
516        source = StudyModeSource(),
517        required = False,
518        readonly = False,
519        )
520
521    #course_studied = schema.Choice(
522    #    title = _(u'Course of Study'),
523    #    source = TranscriptCertificateSource(),
524    #    description = u'Faculty / Department / Course',
525    #    required = True,
526    #    readonly = False,
527    #    )
528
529    #course_changed = schema.Choice(
530    #    title = _(u'Change of Study Course / Transfer'),
531    #    description = u'If yes, select previous course of study.',
532    #    source = TranscriptCertificateSource(),
533    #    readonly = False,
534    #    required = False,
535    #    )
536
537    spillover_level = schema.Choice(
538        title = _(u'Spill-over'),
539        description = u'Any spill-over? If yes, select session of spill-over.',
540        source = academic_sessions_vocab,
541        required = False,
542        readonly = False,
543        )
544
545    purpose = schema.TextLine(
546        title = _(u'Transcript Purpose'),
547        required = False,
548        )
549
550    #order = schema.Choice(
551    #    source = OrderSource(),
552    #    title = _(u'Type of Order'),
553    #    required = True,
554    #    )
555
556    org_name = schema.TextLine(
557        title = _(u'Name of Organization'),
558        required = False,
559        )
560
561    dispatch_address = schema.Text(
562        title = _(u'Recipient Address'),
563        description = u'Addresses (including email address and phone number) '
564                       'to which transcripts should be posted. '
565                       'All addresses must involve same courier charges.',
566        required = True,
567        readonly = False,
568        )
569
570    charge = schema.Choice(
571        title = _(u'Transcript Charge'),
572        source = DestinationCostSource(),
573        required = True,
574        readonly = False,
575        )
576       
577    curriculum = schema.Bool(
578        title = _(u'Including curriculum'),
579        description = u'₦ 5000 will be added to transcript charge.',
580        default = False,
581        required = False,
582        )
583
584    no_copies = schema.Choice(
585        title = _(u'Number of Copies'),
586        description = u'Must correspond with the number of dispatch addresses above.',
587        values=[1, 2, 3, 4],
588        required = False,
589        readonly = False,
590        default = 1,
591        )
592
593    courier_tno = schema.TextLine(
594        title = _(u'Courier Tracking Number'),
595        required = False,
596        )
597
598    #proc_date = FormattedDate(
599    #    title = _(u'Processing Date'),
600    #    required = False,
601    #    #date_format = u'%d/%m/%Y', # Use grok-instance-wide default
602    #    show_year = True,
603    #    )
604
605    #@invariant
606    #def type_of_order(applicant):
607    #    if not applicant.collected and applicant.order != 'o':
608    #        raise Invalid(_("If you haven't collected transcript before, type of order must be 'Student Transcript'."))
609    #    if applicant.order == 'o' and applicant.charge.startswith('cert_'):
610    #        raise Invalid(_("You've selected the wrong transcript charge."))
611    #    if applicant.order == 'c' and not applicant.charge.startswith('cert_'):
612    #        raise Invalid(_("You've selected the wrong transcript charge."))
613
614
615class ICustomApplicant(ICustomUGApplicant, ICustomPGApplicant,
616                       ITranscriptApplicant):
617    """An interface for both types of applicants.
618
619    Attention: The ICustomPGApplicant field seetings will be overwritten
620    by ICustomPGApplicant field settings. If a field is defined
621    in both interfaces zope.schema validates only against the
622    constraints in ICustomUGApplicant. This does not affect the forms
623    since they are build on either ICustomUGApplicant or ICustomPGApplicant.
624    """
625
626    def writeLogMessage(view, comment):
627        """Adds an INFO message to the log file
628        """
629
630    def createStudent():
631        """Create a student object from applicant data
632        and copy applicant object.
633        """
634
635class ICustomUGApplicantEdit(ICustomUGApplicant):
636    """An undergraduate applicant interface for edit forms.
637
638    Here we can repeat the fields from base data and set the
639    `required` and `readonly` attributes to True to further restrict
640    the data access. Or we can allow only certain certificates to be
641    selected by choosing the appropriate source.
642
643    We cannot omit fields here. This has to be done in the
644    respective form page.
645    """
646
647    email = schema.ASCIILine(
648        title = _(u'Email Address'),
649        required = True,
650        constraint=validate_email,
651        )
652
653    phone = PhoneNumber(
654        title = _(u'Phone'),
655        description = u'',
656        required = True,
657        )
658
659    perm_address = schema.Text(
660        title = _(u'Permanent Address'),
661        required = True,
662        )
663
664    next_kin_name = schema.TextLine(
665        title = _(u'Next of Kin Name'),
666        required = True,
667        readonly = False,
668        )
669
670    next_kin_relation = schema.TextLine(
671        title = _(u'Next of Kin Relationship'),
672        required = True,
673        readonly = False,
674        )
675
676    next_kin_address = schema.Text(
677        title = _(u'Next of Kin Address'),
678        required = True,
679        readonly = False,
680        )
681
682    next_kin_phone = PhoneNumber(
683        title = _(u'Next of Kin Phone'),
684        required = True,
685        readonly = False,
686        )
687
688    jamb_reg_number = schema.TextLine(
689        title = _(u'JAMB Registration Number'),
690        required = False,
691        constraint=validate_jamb_reg_number,
692        )
693
694    jamb_subjects = schema.Text(
695        title = _(u'Subjects and Scores'),
696        required = False,
697        )
698
699    jamb_score = schema.Int(
700        title = _(u'Total JAMB Score'),
701        required = False,
702        )
703
704ICustomUGApplicantEdit[
705    'email'].order = ICustomUGApplicant['email'].order
706ICustomUGApplicantEdit[
707    'phone'].order = ICustomUGApplicant['phone'].order
708ICustomUGApplicantEdit[
709    'perm_address'].order = ICustomUGApplicant['perm_address'].order
710ICustomUGApplicantEdit[
711    'next_kin_name'].order = ICustomUGApplicant['next_kin_name'].order
712ICustomUGApplicantEdit[
713    'next_kin_relation'].order = ICustomUGApplicant['next_kin_relation'].order
714ICustomUGApplicantEdit[
715    'next_kin_address'].order = ICustomUGApplicant['next_kin_address'].order
716ICustomUGApplicantEdit[
717    'next_kin_phone'].order = ICustomUGApplicant['next_kin_phone'].order
718
719class ICustomPGApplicantEdit(INigeriaPGApplicantEdit):
720    """A postgraduate applicant interface for editing.
721
722    Here we can repeat the fields from base data and set the
723    `required` and `readonly` attributes to True to further restrict
724    the data access. Or we can allow only certain certificates to be
725    selected by choosing the appropriate source.
726
727    We cannot omit fields here. This has to be done in the
728    respective form page.
729    """
730
731class ICustomApplicantOnlinePayment(INigeriaApplicantOnlinePayment):
732    """An applicant payment via payment gateways.
733
734    """
735
736class IPUTMEApplicantEdit(IPUTMEApplicantEdit):
737    """An undergraduate applicant interface for editing.
738
739    Here we can repeat the fields from base data and set the
740    `required` and `readonly` attributes to True to further restrict
741    the data access. Or we can allow only certain certificates to be
742    selected by choosing the appropriate source.
743
744    We cannot omit fields here. This has to be done in the
745    respective form page.
746    """
747
748class ICustomApplicantUpdateByRegNo(INigeriaApplicantUpdateByRegNo):
749    """Representation of an applicant.
750
751    Skip regular reg_number validation if reg_number is used for finding
752    the applicant object.
753    """
Note: See TracBrowser for help on using the repository browser.