source: main/kofacustom.edopoly/trunk/src/kofacustom/edopoly/applicants/interfaces.py @ 17521

Last change on this file since 17521 was 17370, checked in by Henrik Bettermann, 21 months ago

Implement transcript application.

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