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

Last change on this file since 17207 was 17154, checked in by Henrik Bettermann, 2 years ago

Make many fields required.

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