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

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

Implement transcript application (fee calculation not yet configured).

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