source: WAeUP_SRP/trunk/Students.py @ 962

Last change on this file since 962 was 961, checked in by joachim, 18 years ago

string type for pume result

  • Property svn:keywords set to Id
File size: 48.0 KB
Line 
1#-*- mode: python; mode: fold -*-
2# $Id: Students.py 961 2006-11-28 15:19:13Z joachim $
3from string import Template
4from Globals import InitializeClass
5from AccessControl import ClassSecurityInfo
6from AccessControl.SecurityManagement import newSecurityManager
7from zExceptions import BadRequest
8from Products.ZCatalog.ZCatalog import ZCatalog
9from Products.CMFCore.utils import UniqueObject, getToolByName
10from Products.CMFCore.permissions import View
11from Products.CMFCore.permissions import ModifyPortalContent
12from Products.CPSCore.CPSBase import CPSBase_adder, CPSBaseFolder
13#from Products.CPSCore.CPSBase import CPSBaseDocument as BaseDocument
14from Products.CPSDocument.CPSDocument import CPSDocument
15from Products.CPSCore.CPSBase import CPSBaseBTreeFolder as BaseBTreeFolder
16from Products.CPSCore.CPSMembershipTool import CPSUnrestrictedUser
17from Products.WAeUP_SRP.Academics import makeCertificateCode
18import logging
19import csv,re
20import Globals
21p_home = Globals.package_home(globals())
22i_home = Globals.INSTANCE_HOME
23MAX_TRANS = 100
24
25def makeCertificateCode(code): ###(
26    code = code.replace('.','')
27    code = code.replace('(','')
28    code = code.replace(')','')
29    code = code.replace('/','')
30    code = code.replace(' ','')
31    code = code.replace('_','')
32    return code
33
34###)
35
36def getInt(s): ###(
37    try:
38        return int(s)
39    except:
40        return 0
41
42def getFloat(s):
43    try:
44        return float(s)
45    except:
46        return 0.0
47
48###)
49
50def getStudentByRegNo(self,reg_no): ###(
51    """search student by JAMB Reg No and return StudentFolder"""
52    search = ZCatalog.searchResults(self.portal_catalog,{'meta_type': 'StudentApplication',
53                                  'SearchableText': reg_no,
54                                  })
55    if len(search) < 1:
56        return None
57    return search[0].getObject().aq_parent
58
59###)
60
61class StudentsFolder(CPSDocument): ###(
62    """
63    WAeUP container for the various WAeUP containers data
64    """
65    meta_type = 'StudentsFolder'
66    portal_type = meta_type
67    security = ClassSecurityInfo()
68
69    security.declareProtected(ModifyPortalContent,"loadFullTimeStudentsFromCSV")###(
70    def loadFullTimeStudentsFromCSV(self):
71        """load Fulltime Studentdata from CSV values"""
72        import transaction
73        import random
74        tr_count = 0
75        name = 'short_full_time'
76        no_import = False
77        if not no_import:
78            no_import = open("%s/import/%s_not_imported.csv" % (i_home,name),"w")
79            no_import.write('"MatricNo","EntryRegNo","CurrentSession","StudentLevel","fullname","FirstName","MiddleName","Lastname","FormerSurname","Sex","Nationality","State","LGA","PermanentAddress","PermanentAddressCity","CampusAddress","PhoneNumber","Emailaddress","Mode","CourseMajor","Faculty","Dept"\n')
80        logger = logging.getLogger('%s_import' % name)
81        logger.info('Start loading from %s.csv' % name)
82        pwlist  = []
83        pwlist.append('"student_id","firstname","middlename","lastname","matric_no","jamb_reg_no","access_code"')
84        pwl_template = Template('"$student_id","$firstname","$middlename","$lastname","$matric_no","$jamb_reg_no","$access_code"')
85        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
86        try:
87            students = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
88        except:
89            logger.error('Error reading %s.csv' % name)
90            return
91        l = self.portal_catalog({'meta_type': "StudentClearance",})
92        matrics = []
93        for s in l:
94            matrics.append(s.getObject().getContent().matric_no)
95        print matrics
96        l = self.portal_catalog({'meta_type': "Certificate"})
97        certs = {}
98        for c in l:
99            ca,ac,fa,dep_id,co,certcode = c.relative_path.split('/')
100            cid = "%(dep_id)s_%(certcode)s" % vars()
101            certs[cid] = c.getObject()
102        for student in students:
103            logger.info('processing "%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
104            sid = student.get('MatricNo')
105            if sid == "":
106                em = 'Empty MatricNo\n'
107                logger.info(em)
108                no_import.write(em)
109                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
110                continue
111            certcode = makeCertificateCode(student.get('CourseMajor'))
112            dep_id = student.get('Dept')
113            fac_id = student.get('Faculty')
114            cid = "%(dep_id)s_%(certcode)s" % vars()
115            if cid not in certs.keys():
116                em = 'Certificate with ID %s %s not found\n' % (certcode, student.get('CourseMajor'))
117                logger.info(em)
118                no_import.write(em)
119                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
120                continue
121            certificate_doc = certs[cid].getContent()
122            level = student.get('StudentLevel')
123            try:
124                int(level)
125            except:
126                em = 'Student with ID %(MatricNo)s StudentLevel is empty\n' % student
127                logger.info(em)
128                no_import.write(em)
129                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
130                continue
131            matric_no = student.get('MatricNo')
132            if matric_no not in matrics:
133                matrics.append(matric_no)
134                sid = self.generateStudentId(student.get('Lastname')[0])
135                #self.log('Creating Faculty %(id)s = %(Title)s' % faculty)
136                students_folder.invokeFactory('Student', sid)
137                logger.info('%(tr_count)s: Creating Student with ID %(sid)s Matric_no %(matric_no)s ' % vars())
138                student_obj = getattr(self,sid)
139                access_code = "%d" % random.randint(1000000000,9999999999)
140                student_obj.getContent().makeStudentMember(sid,access_code,)
141                pwl_dict = {'student_id': sid,'access_code':access_code}
142                student_obj.invokeFactory('StudentApplication','application')
143                application = student_obj.application
144                da = {'Title': 'Application Data'}
145                student_obj.invokeFactory('StudentPersonal','personal')
146                da['jamb_reg_no'] = student.get('EntryRegNo')
147                personal = student_obj.personal
148                dp = {'Title': 'Personal Data'}
149                student_obj.invokeFactory('StudentClearance','clearance')
150                clearance = student_obj.clearance
151                dc = {'Title': 'Clearance/Eligibility Record'}
152                dc['matric_no'] = matric_no
153                state = student.get('State')
154                lga = student.get('LGA')
155                if state and lga:
156                    lga =  state + ' / ' + lga
157                else:
158                    lga = "None"
159                dc['lga'] = lga
160                dc['nationality'] = student.get('Nationality')
161                dc['email'] = student.get('Emailaddress')
162                dp['firstname'] = student.get('FirstName')
163                dp['middlename'] = student.get('MiddleName')
164                dp['lastname'] = student.get('Lastname')
165                dp['former_surname'] = student.get('FormerSurname')
166                dp['sex'] = student.get('Sex') == 'F'
167                dp['perm_address'] = student.get('PermanentAddress')
168                dp['perm_city'] = student.get('PermanentAddressCity')
169                dp['campus_address'] = student.get('CampusAddress')
170                dp['phone'] = student.get('PhoneNumber')
171                application.getContent().edit(mapping=da)
172                personal.getContent().edit(mapping=dp)
173                clearance.getContent().edit(mapping=dc)
174                #
175                # Study Course
176                #
177                student_obj.invokeFactory('StudentStudyCourse','study_course')
178                studycourse = student_obj.study_course
179                dsc = {}
180                from_certificate = ['title',
181                                   'max_elect',
182                                   'max_pass',
183                                   'n_core',
184                                   'nr_years',
185                                   'probation_credits',
186                                   'promotion_credits',
187                                   'start_level',
188                                  ]
189                for f in from_certificate:
190                    dsc[f] = getattr(certificate_doc,f)
191                dsc['faculty'] = fac_id
192                dsc['department'] = dep_id
193                dsc['study_course'] = certcode
194                css = student.get('CurrentSession') or '2004-2005'
195                cs = int(css.split('-')[0]) - 2000
196                cl = int(student.get('StudentLevel') or '100')/100
197                dsc['entry_session'] = "200%s" % (cs - cl)
198                dsc['clr_ac_pin'] = access_code
199                studycourse.getContent().edit(mapping=dsc)
200                #
201                # Level
202                #
203##                l = getattr(studycourse,level,None)
204##                if 0 and l is None:
205##                    #self.log('Creating Department %(DeptCode)s = %(Description)s' % dep)
206##                    logger.info('Creating Level %(StudentLevel)s for %(fullname)s' % student)
207##                    studycourse.invokeFactory('StudentStudyLevel', level)
208##                    l = getattr(studycourse, level)
209##                    certificate = certs[certcode]
210##                    cert_level = getattr(certificate,level,None)
211##                    if cert_level is None:
212##                        logger.info('Level %(level)s not in %(certcode)s' % vars())
213##                    l.getContent().edit(mapping={'Title': "Level %s" % level})
214            else:
215                em = 'Student with ID %(MatricNo)s %(fullname)s already exists\n' % student
216                logger.info(em)
217                no_import.write(em)
218                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
219                continue
220            if tr_count > MAX_TRANS:
221                transaction.commit()
222                em = 'Transaction commited\n' % student
223                logger.info(em)
224                tr_count = 0
225            tr_count += 1
226            pwl_dict.update(dc)
227            pwl_dict.update(da)
228            pwl_dict.update(dp)
229            wftool = self.portal_workflow
230            pwlist.append(pwl_template.substitute(pwl_dict))
231            wftool.doActionFor(student_obj,'clear_and_validate')
232            student_obj.manage_setLocalRoles(sid, ['Owner',])
233            wftool.doActionFor(application,'close')
234            application.manage_setLocalRoles(sid, ['Owner',])
235            wftool.doActionFor(clearance,'close')
236            clearance.manage_setLocalRoles(sid, ['Owner',])
237            wftool.doActionFor(personal,'close')
238            personal.manage_setLocalRoles(sid, ['Owner',])
239            wftool.doActionFor(studycourse,'close_for_edit')
240            studycourse.manage_setLocalRoles(sid, ['Owner',])
241        open("%s/import/pwlist-%s.csv" % (i_home,name),"w+").write('\n'.join(pwlist))
242        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
243    ###)
244
245    security.declareProtected(ModifyPortalContent,"loadPumeResultsFromCSV")###(
246    def loadPumeResultsFromCSV(self):
247        """load Fulltime Studentdata from CSV values"""
248        import transaction
249        import random
250        from pdb import set_trace
251        wftool = self.portal_workflow
252        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
253        csv_d = {'jamb_reg_no': "JAMBRegno",
254                 'jamb_lastname': "Name",
255                 #'pume_options': "Options",
256                 #'session': "Session",
257                 #'days': "Days",
258                 #'response': "Responce",
259                 #'wrong': "Wrong",
260                 #'pume_eng_score': "EngScore",
261                 #'pume_gen_score': "GenScore",
262                 'pume_tot_score': "Score",
263                 #'batch': "Batch",
264                 #'serial': "SerialNo",
265                 #'jamb_score': "JambScore",
266                 #'omitted':"Omitted",
267                 #'search_key': "SearchKey",
268                 'jamb_sex': "Sex",
269                 'fac1': "Faculty",
270                 'dep': "Dept",
271                 #'fac2': "Fac2",
272                 'jamb_first_cos': "Course Code",
273                 'stud_status':"Admission Status",
274                 #'registered': "Registered",
275                 #'jamb_state': "State",
276                 #'eng_fail': "EngFail",
277                 #'gen_fail': "GenFail",
278                 #'un_ans_eng': "UnAnsEng",
279                 #'un_ans_eng': "UnAnsGen",
280                 #'total_ans': "TotalUnAns",
281                 #'dept': "Dept",
282                 #'jamb_second_cos': "Course2",
283                 #'jamb_third_cos': "course3",
284                 }
285        csv_fields = [f[1] for f in csv_d.items()]
286        tr_count = 0
287        total = 0
288        #name = 'pume_results'
289        name = 'pup'
290        no_import = []
291        s = ','.join(['"(%s)"' % fn for fn in csv_fields])
292        no_import.append('%s\n' % s)
293        logger = logging.getLogger('%s_import' % name)
294        logger.info('Start loading from %s.csv' % name)
295        #set_trace()
296        try:
297            result = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
298        except:
299            logger.error('Error reading %s.csv' % name)
300            return
301        for jamb in result:
302            format = ','.join(['"%%(%s)s"' % fn for fn in csv_fields])
303            processing = "processing %s" % format
304            logger.info(processing % jamb)
305            jamb_reg_no = jamb.get(csv_d['jamb_reg_no'])
306            #import pdb;pdb.set_trace()
307            res = self.portal_catalog({'portal_type': "StudentApplication",
308                                     'SearchableText': jamb_reg_no })
309            if res:
310                em = 'Student with REG-NO %s already exists\n' % jamb_reg_no
311                logger.info(em)
312                no_import.append(em)
313                no_import.append(format % jamb)
314                continue
315            cert_id = makeCertificateCode(jamb.get(csv_d['jamb_first_cos']))
316            res = self.portal_catalog({'portal_type': "Certificate",
317                                     'id': cert_id })
318            if len(res) < 1:
319                em = 'No Certificate with ID %s \n' % cert_id
320                logger.info(em)
321                no_import.append(em)
322                no_import.append(format % jamb)
323                continue
324            cert = res[0].getObject()
325            cert_path = res[0].getPath()
326            cert_doc = cert.getContent()
327            jamb_name = jamb.get(csv_d['jamb_lastname'])
328            jamb_name.replace('>','')
329            names = jamb_name.split()
330            letter = names[-1][0].upper()
331            sid = self.generateStudentId(letter)
332            not_created = True
333            while not_created:
334                try:
335                    students_folder.invokeFactory('Student', sid)
336                    not_created = False
337                except BadRequest:
338                    sid = self.generateStudentId(letter)
339            tr_count += 1
340            logger.info('%(total)s+%(tr_count)s: Creating Student with ID %(sid)s REG-NO %(jamb_reg_no)s ' % vars())
341            student = getattr(self,sid)
342            student.manage_setLocalRoles(sid, ['Owner',])
343            student.invokeFactory('StudentClearance','clearance')
344            #wftool.doActionFor(student.clearance,'open')
345            dp = {'Title': 'Clearance/Eligibility Record'}
346            student.clearance.manage_setLocalRoles(sid, ['Owner',])
347            student.invokeFactory('StudentPume','pume')
348            dp = {'Title': 'Pume Data'}
349            student.invokeFactory('StudentApplication','application')
350            da = {'Title': 'Application Data'}
351            da["jamb_lastname"] = jamb_name
352            da_fields = ('jamb_reg_no',
353                         'jamb_sex',
354                         #'jamb_state',
355                         #'jamb_score',
356                         'jamb_first_cos',
357                         'jamb_sex',
358                         #'jamb_state',
359                         #'jamb_first_cos',
360                         #'jamb_second_cos',
361                         )
362            for f in da_fields:
363                da[f] = jamb.get(csv_d[f])
364            app = student.application
365            app.getContent().edit(mapping=da)
366            app.manage_setLocalRoles(sid, ['Owner',])
367            #wftool.doActionFor(app,'close')
368            dp_fields = (
369                         #'pume_eng_score',
370                         #'pume_gen_score',
371                         'pume_tot_score',
372                         )
373            dp['pume_tot_score'] = jamb.get(csv_d[f]) or "No Option Shaded"
374            pume = student.pume
375            pume.getContent().edit(mapping=dp)
376            #wftool.doActionFor(pume,'close')
377            pume.manage_setLocalRoles(sid, ['Owner',])
378            #
379            # Study Course
380            #
381            if jamb.get(csv_d['stud_status']) == "Admitted":
382                wftool.doActionFor(student,'pume_pass')
383                wftool.doActionFor(student,'admit')
384            else:
385                wftool.doActionFor(student,'pume_fail')
386                wftool.doActionFor(student,'reject_admission')
387                continue
388            student.invokeFactory('StudentStudyCourse','study_course')
389            study_course = student.study_course
390            dsc = {}
391            from_certificate = ['title',
392                               'max_elect',
393                               'max_pass',
394                               'n_core',
395                               'nr_years',
396                               'probation_credits',
397                               'promotion_credits',
398                               'start_level',
399                              ]
400            for f in from_certificate:
401                dsc[f] = getattr(cert_doc,f)
402            cpl = cert_path.split('/')
403            dsc['faculty'] = cpl[-4]
404            dsc['department'] = cpl[-3]
405            dsc['study_course'] = cert_id
406            dsc['entry_session'] = "2006/2007" #jamb.get(csv_d['session'])
407            study_course.getContent().edit(mapping=dsc)
408            student.getContent().createSubObjects()
409            if tr_count > MAX_TRANS:
410                em = '%d transactions commited\n' % tr_count
411                transaction.commit()
412                logger.info(em)
413                total += tr_count
414                tr_count = 0
415        if len(no_import) > 1:
416            open("%s/import/%s_not_imported.csv" % (i_home,name),"w").write(
417                     '\n'.join(no_import))
418        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
419    ###)
420
421    security.declareProtected(ModifyPortalContent,"OLDloadPumeResultsFromCSV")###(
422    def OLDloadPumeResultsFromCSV(self):
423        """load Fulltime Studentdata from CSV values"""
424        import transaction
425        import random
426        wftool = self.portal_workflow
427        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
428        csv_d = {'jamb_reg_no': "JAMBRegno",
429                 'jamb_lastname': "Name",
430                 'pume_options': "Options",
431                 'session': "Session",
432                 'days': "Days",
433                 'response': "Responce",
434                 'wrong': "Wrong",
435                 'pume_eng_score': "EngScore",
436                 'pume_gen_score': "GenScore",
437                 'pume_tot_score': "Score",
438                 'batch': "Batch",
439                 'serial': "SerialNo",
440                 'jamb_score': "JambScore",
441                 'omitted':"Omitted",
442                 'search_key': "SearchKey",
443                 'jamb_sex': "Sex",
444                 'fac1': "Fac1",
445                 'fac2': "Fac2",
446                 'jamb_first_cos': "CourseofStudy",
447                 'stud_status':"StudStatus",
448                 'registered': "Registered",
449                 'jamb_state': "State",
450                 'eng_fail': "EngFail",
451                 'gen_fail': "GenFail",
452                 'un_ans_eng': "UnAnsEng",
453                 'un_ans_eng': "UnAnsGen",
454                 'total_ans': "TotalUnAns",
455                 'dept': "Dept",
456                 'jamb_second_cos': "Course2",
457                 'jamb_third_cos': "course3",
458                 }
459        csv_fields = [f[1] for f in csv_d.items()]
460        tr_count = 0
461        name = 'pume_results'
462        no_import = []
463        s = ','.join(['"(%s)"' % fn for fn in csv_fields])
464        no_import.append('%s\n' % s)
465        logger = logging.getLogger('%s_import' % name)
466        logger.info('Start loading from %s.csv' % name)
467        try:
468            result = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
469        except:
470            logger.error('Error reading %s.csv' % name)
471            return
472        for jamb in result:
473            format = ','.join(['"%%(%s)s"' % fn for fn in csv_fields])
474            processing = "processing %s" % format
475            logger.info(processing % jamb)
476            jamb_reg_no = jamb.get(csv_d['jamb_reg_no'])
477            #import pdb;pdb.set_trace()
478            res = self.portal_catalog({'portal_type': "StudentApplication",
479                                     'jamb_reg_no': jamb_reg_no })
480            if res:
481                em = 'Student with REG-NO %s already exists\n' % jamb_reg_no
482                logger.info(em)
483                no_import.append(em)
484                no_import.append(format % jamb)
485                continue
486            cert_id = jamb.get(csv_d['jamb_first_cos']).upper()
487            res = self.portal_catalog({'portal_type': "Certificate",
488                                     'id': cert_id })
489            if len(res) < 1:
490                em = 'No Certificate with ID %s \n' % cert_id
491                logger.info(em)
492                no_import.append(em)
493                no_import.append(format % jamb)
494                continue
495            cert = res[0].getObject()
496            cert_path = res[0].getPath()
497            cert_doc = cert.getContent()
498            jamb_name = jamb.get(csv_d['jamb_lastname'])
499            jamb_name.replace('>','')
500            names = jamb_name.split()
501            letter = names[-1][0].upper()
502            sid = self.generateStudentId(letter)
503            not_created = True
504            while not_created:
505                try:
506                    students_folder.invokeFactory('Student', sid)
507                    not_created = False
508                except BadRequest:
509                    sid = self.generateStudentId(letter)
510            logger.info('%(tr_count)s: Creating Student with ID %(sid)s REG-NO %(jamb_reg_no)s ' % vars())
511            student = getattr(self,sid)
512            student.manage_setLocalRoles(sid, ['Owner',])
513            student.invokeFactory('StudentClearance','clearance')
514            #wftool.doActionFor(student.clearance,'open')
515            dp = {'Title': 'Clearance/Eligibility Record'}
516            student.clearance.manage_setLocalRoles(sid, ['Owner',])
517            student.invokeFactory('StudentPume','pume')
518            dp = {'Title': 'Pume Data'}
519            student.invokeFactory('StudentApplication','application')
520            da = {'Title': 'Application Data'}
521            da["jamb_lastname"] = jamb_name
522            da_fields = ('jamb_reg_no',
523                         'jamb_sex',
524                         'jamb_state',
525                         'jamb_score',
526                         'jamb_first_cos',
527                         'jamb_sex',
528                         'jamb_state',
529                         'jamb_first_cos',
530                         'jamb_second_cos',
531                         )
532            for f in da_fields:
533                da[f] = jamb.get(csv_d[f])
534            app = student.application
535            app.getContent().edit(mapping=da)
536            app.manage_setLocalRoles(sid, ['Owner',])
537            #wftool.doActionFor(app,'close')
538            dp_fields = (
539                         'pume_eng_score',
540                         'pume_gen_score',
541                         'pume_tot_score',
542                         )
543            for f in dp_fields:
544                dp[f] = float(jamb.get(csv_d[f]))
545            pume = student.pume
546            pume.getContent().edit(mapping=dp)
547            #wftool.doActionFor(pume,'close')
548            pume.manage_setLocalRoles(sid, ['Owner',])
549            #
550            # Study Course
551            #
552            student.invokeFactory('StudentStudyCourse','study_course')
553            study_course = student.study_course
554            dsc = {}
555            from_certificate = ['title',
556                               'max_elect',
557                               'max_pass',
558                               'n_core',
559                               'nr_years',
560                               'probation_credits',
561                               'promotion_credits',
562                               'start_level',
563                              ]
564            for f in from_certificate:
565                dsc[f] = getattr(cert_doc,f)
566            cpl = cert_path.split('/')
567            dsc['faculty'] = cpl[-4]
568            dsc['department'] = cpl[-3]
569            dsc['study_course'] = cert_id
570            dsc['entry_session'] = jamb.get(csv_d['session'])
571            study_course.getContent().edit(mapping=dsc)
572            student.getContent().createSubObjects()
573            if dp['pume_tot_score']>49:
574                wftool.doActionFor(student,'pume_pass')
575                wftool.doActionFor(student,'admit')
576            else:
577                wftool.doActionFor(student,'pume_fail')
578                wftool.doActionFor(student,'reject_admission')
579            if len(no_import) > 1:
580                open("%s/import/%s_not_imported.csv" % (i_home,name),"w").write(
581                     '\n'.join(no_import))
582        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
583    ###)
584
585    security.declareProtected(ModifyPortalContent,"loadFullTimeStudentsResultsFromCSV") ###(
586    def loadFullTimeStudentsResultsFromCSV(self):
587        """load Fulltime Studentdata from CSV values"""
588        #return
589        level_wf_actions = {}
590        level_wf_actions["SUCCESSFUL STUDENT"] = "pass_A"
591        level_wf_actions["STUDENT WITH CARRYOVER COURSES"] = "pass_B"
592        level_wf_actions["STUDENT FOR PROBATION"] = "probate_C"
593        level_wf_actions["STUDENT ON PROBATION/TRANSFER"] = "reject_D"
594        import transaction
595        wftool = self.portal_workflow
596        tr_count = 0
597        name = 'short_full_time_results_2004_2005'
598        no_import = False
599        if not no_import:
600            no_import = open("%s/import/%s_not_imported.csv" % (i_home,name),"w")
601            no_import.write('"Matnumber","CosCode","Ansbook","CosStuatus","Session","Mat_Cos","Score","CarryLevel","Grade","Weight","Semster","Verdict","Level","id","GPA"\n')
602        logger = logging.getLogger('%s_import' % name)
603        logger.info('Start loading from %s.csv' % name)
604        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
605        try:
606            results = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
607        except:
608            logger.error('Error reading %s.csv' % name)
609            return
610        l = self.portal_catalog({'meta_type': "Course"})
611        courses = {}
612        for c in l:
613            courses[c.id] = c.getObject()
614        level_changed = False
615        student_changed = False
616        sid = ''
617        #import pdb;pdb.set_trace()
618        for result in results:
619            temp_sid = result.get('Matnumber')
620            if temp_sid != sid:
621                student_changed = True
622                res = self.portal_catalog({'meta_type': "StudentClearance",
623                                         'SearchableText': temp_sid })
624                if not res:
625                    em = 'Student with ID %(Matnumber)s not found\n' % result
626                    logger.info(em)
627                    no_import.write(em)
628                    no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
629                    continue
630                elif len(res) > 1:
631                    em = 'More than one Student with ID %(Matnumber)s found\n' % result
632                    logger.info(em)
633                    no_import.write(em)
634                    no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
635                    continue
636                sid = temp_sid
637                sf = res[0].getObject().aq_parent
638                sc = getattr(sf,'study_course')
639                level = ''
640            else:
641                student_changed = False
642            course = result.get('CosCode')
643            if course not in courses.keys():
644                em = 'Course with ID %(CosCode)s not found\n' % result
645                logger.info(em)
646                no_import.write(em)
647                no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
648                continue
649            course_doc = courses[course].getContent()
650            temp_level = result.get('Level')
651            student_id = sf.getId()
652            result['StudentId'] = student_id
653            if temp_level != level:
654                try:
655                    int(temp_level)
656                except:
657                    em = 'Result with ID %(Matnumber)s Course %(CosCode)s Level is empty\n' % result
658                    logger.info(em)
659                    no_import.write(em)
660                    no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
661                    continue
662                level_changed = True
663                if 'dlev' in vars().keys():
664                    wftool.doActionFor(l,level_wf_actions[dlev['verdict']])
665                level = temp_level
666                l = getattr(sc,level,None)
667                if l is None:
668                    logger.info('Creating Level %(Level)s for %(StudentId)s %(Matnumber)s' % result)
669                    sc.invokeFactory('StudentStudyLevel', level)
670                    l = getattr(sc, level)
671                    l.manage_setLocalRoles(student_id, ['Owner',])
672            else:
673                level_changed = False
674            cr = getattr(l,course,None)
675            if cr is None:
676                logger.info('Creating Course %(CosCode)s for %(StudentId)s %(Matnumber)s in Level %(Level)s' % result)
677                l.invokeFactory('StudentCourseResult',course)
678            cr = getattr(l,course)
679            dcr = {}
680            from_course = ['title',
681                           'credits',
682                           'passmark',
683                           ]
684            for f in from_course:
685                dcr[f] = getattr(course_doc,f)
686            dlev = {}
687            dcr['ansbook'] = result.get('Ansbook')
688            dcr['semester'] = getInt(result.get('Semster'))
689            dcr['status'] = result.get('CosStuatus')
690            dcr['score'] = getInt(result.get('Score'))
691            dlev['session'] = result.get('Session')
692            dcr['carry_level'] = result.get('CarryLevel')
693            dcr['grade'] = result.get('Grade')
694            dcr['weight'] = result.get('Weight')
695            dlev['verdict'] = result.get('Verdict')
696            dcr['import_id'] = result.get('id')
697            gpa = result.get('GPA').replace(',','.')
698            dlev['imported_gpa'] = getFloat(gpa)
699            cr.getContent().edit(mapping = dcr)
700            cr.manage_setLocalRoles(student_id, ['Owner',])
701            l.getContent().edit(mapping = dlev)
702            if tr_count > MAX_TRANS:
703                transaction.commit()
704                tr_count = 0
705            tr_count += 1
706            wftool.doActionFor(cr,'close')
707        wftool.doActionFor(l,level_wf_actions[dlev['verdict']])
708        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
709
710###)
711
712    security.declareProtected(ModifyPortalContent,"loadJAMBFromCSV")###(
713    def loadJAMBFromCSV(self):
714        """load JAMB data from CSV values"""
715        #return
716        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
717        import transaction
718        tr_count = 0
719        name = 'SampleJAMBDataII'
720        wftool = self.portal_workflow
721        no_import = False
722        if not no_import:
723            no_import = open("%s/import/%s_not_imported.csv" % (i_home,name),"w")
724            no_import.write('REG-NO,NAME,SEX,STATE,LGA,ENG-SCORE,SUBJ1,SUBJ1-SCORE,SUBJ2,SUBJ2-SCORE,SUBJ3,SUBJ3-SCORE,AGGREGATE,UNIV1,FACULTY1,COURSE1,UNIV2,FACULTY2,COURSE2')
725        logger = logging.getLogger('%s_import' % name)
726        logger.info('Start loading from %s.csv' % name)
727        try:
728            result = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
729        except:
730            logger.error('Error reading %s.csv' % name)
731            return
732        for jamb in result:
733            logger.info('processing %(REG-NO)s,%(NAME)s,%(SEX)s,%(STATE)s,%(LGA)s,%(ENG-SCORE)s,%(SUBJ1)s,%(SUBJ1-SCORE)s,%(SUBJ2)s,%(SUBJ2-SCORE)s,%(SUBJ3)s,%(SUBJ3-SCORE)s,%(AGGREGATE)s,%(UNIV1)s,%(FACULTY1)s,%(COURSE1)s,%(UNIV2)s,%(FACULTY2)s,%(COURSE2)s\n' % jamb)
734            jamb_reg_no = jamb.get('REG-NO')
735            res = self.portal_catalog({'meta_type': "StudentApplication",
736                                     'jamb_reg_no': jamb_reg_no })
737            if res:
738                em = 'Student with REG-NO %(REG-NO)s already exists\n' % jamb
739                logger.info(em)
740                no_import.write(em)
741                no_import.write('%(REG-NO)s,%(NAME)s,%(SEX)s,%(STATE)s,%(LGA)s,%(ENG-SCORE)s,%(SUBJ1)s,%(SUBJ1-SCORE)s,%(SUBJ2)s,%(SUBJ2-SCORE)s,%(SUBJ3)s,%(SUBJ3-SCORE)s,%(AGGREGATE)s,%(UNIV1)s,%(FACULTY1)s,%(COURSE1)s,%(UNIV2)s,%(FACULTY2)s,%(COURSE2)s\n' % jamb)
742                continue
743            jamb_name = jamb.get("NAME")
744            jamb_name.replace('>','')
745            names = jamb_name.split()
746            letter = names[-1][0].upper()
747            sid = self.generateStudentId(letter)
748            not_created = True
749            while not_created:
750                try:
751                    students_folder.invokeFactory('Student', sid)
752                    not_created = False
753                except BadRequest:
754                    sid = self.generateStudentId(letter)
755            logger.info('%(tr_count)s: Creating Student with ID %(sid)s REG-NO %(jamb_reg_no)s ' % vars())
756            student = getattr(self,sid)
757            student.manage_setLocalRoles(sid, ['Owner',])
758            student.invokeFactory('StudentApplication','application')
759            da = {'Title': 'Application Data'}
760            da["jamb_reg_no"] = jamb.get("REG-NO")
761            da["jamb_lastname"] = jamb_name
762            da["jamb_sex"] = jamb.get("SEX")
763            da["jamb_state"] = jamb.get("STATE")
764            da["jamb_lga"] = jamb.get("LGA")
765            da["jamb_score"] = jamb.get("AGGREGATE")
766            da["jamb_first_cos"] = jamb.get("COURSE1")
767            da["jamb_second_cos"] = jamb.get("COURSE2")
768            da["jamb_first_uni"] = jamb.get("UNIV1")
769            da["jamb_second_uni"] = jamb.get("UNIV2")
770            app = student.application
771            app_doc = app.getContent()
772            app_doc.edit(mapping=da)
773            #wftool.doActionFor(app,'open',dest_container=app)
774            app.manage_setLocalRoles(sid, ['Owner',])
775            student.getContent().createSubObjects()
776        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
777    ###)
778
779
780    security.declareProtected(View,"fixOwnership")
781    def fixOwnership(self):
782        """fix Ownership"""
783        for s in self.portal_catalog(meta_type = 'Student'):
784            student = s.getObject()
785            sid = s.getId
786            import pdb;pdb.set_trace()
787            student.application.manage_setLocalRoles(sid, ['Owner',])
788            student.personal.manage_setLocalRoles(sid, ['Owner',])
789
790    security.declareProtected(View,"Title")
791    def Title(self):
792        """compose title"""
793        return "Student Section"
794
795    def generateStudentId(self,letter): ###(
796        import random
797        r = random
798        if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
799            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
800        students = self.portal_catalog(meta_type = "StudentsFolder")[-1]
801        sid = "%c%d" % (letter,r.randint(99999,1000000))
802        while hasattr(students, sid):
803            sid = "%c%d" % (letter,r.randint(99999,1000000))
804        return sid
805        #return "%c%d" % (r.choice('ABCDEFGHKLMNPQRSTUVWXY'),r.randint(99999,1000000))
806    ###)
807
808InitializeClass(StudentsFolder)
809
810def addStudentsFolder(container, id, REQUEST=None, **kw):
811    """Add a Student."""
812    ob = StudentsFolder(id, **kw)
813    return CPSBase_adder(container, ob, REQUEST=REQUEST)
814###)
815
816class Student(CPSDocument): ###(
817    """
818    WAeUP Student container for the various student data
819    """
820    meta_type = 'Student'
821    portal_type = meta_type
822    security = ClassSecurityInfo()
823
824    security.declareProtected(View,"Title")
825    def Title(self):
826        """compose title"""
827        reg_nr = self.getId()[1:]
828        data = getattr(self,'personal',None)
829        if data:
830            content = data.getContent()
831            return "%s %s" % (content.firstname,content.lastname)
832        data = getattr(self,'application',None)
833        if data:
834            content = data.getContent()
835            return "%s" % (content.jamb_lastname)
836        return self.title
837
838    security.declarePrivate('makeStudentMember') ###(
839    def makeStudentMember(self,sid,password='uNsEt'):
840        """make the student a member"""
841        membership = self.portal_membership
842        membership.addMember(sid,
843                             password ,
844                             roles=('Member',
845                                     'Student',
846                                     ),
847                             domains='',
848                             properties = {'memberareaCreationFlag': False,
849                                           'homeless': True},)
850        member = membership.getMemberById(sid)
851        self.portal_registration.afterAdd(member, sid, password, None)
852        self.manage_setLocalRoles(sid, ['Owner',])
853
854###)
855
856    security.declareProtected(View,'createSubObjects') ###(
857    def createSubObjects(self):
858        """make the student a member"""
859        dp = {'Title': 'Personal Data'}
860        app_doc = self.application.getContent()
861        names = app_doc.jamb_lastname.split()
862        if len(names) == 3:
863            dp['firstname'] = names[0].capitalize()
864            dp['middlename'] = names[1].capitalize()
865            dp['lastname'] = names[2].capitalize()
866        elif len(names) == 2:
867            dp['firstname'] = names[0].capitalize()
868            dp['lastname'] = names[1].capitalize()
869        else:
870            dp['lastname'] = app_doc.jamb_lastname
871        dp['sex'] = app_doc.jamb_sex == 'F'
872        dp['lga'] = "%s/%s" % (app_doc.jamb_state,app_doc.jamb_lga )
873        proxy = self.aq_parent
874        proxy.invokeFactory('StudentPersonal','personal')
875        per = proxy.personal
876        per_doc = per.getContent()
877        per_doc.edit(mapping = dp)
878        per.manage_setLocalRoles(proxy.getId(), ['Owner',])
879        #self.portal_workflow.doActionFor(per,'open',dest_container=per)
880
881###)
882
883InitializeClass(Student)
884
885def addStudent(container, id, REQUEST=None, **kw):
886    """Add a Student."""
887    ob = Student(id, **kw)
888    return CPSBase_adder(container, ob, REQUEST=REQUEST)
889
890###)
891
892class StudentAccommodation(CPSDocument): ###(
893    """
894    WAeUP Student container for the various student data
895    """
896    meta_type = 'StudentAccommodation'
897    portal_type = meta_type
898    security = ClassSecurityInfo()
899
900    security.declareProtected(View,"Title")
901    def Title(self):
902        """compose title"""
903        content = self.getContent()
904        #return "Accommodation Data for %s %s" % (content.firstname,content.lastname)
905        return "Accommodation Data for Session %s" % content.session
906
907
908InitializeClass(StudentAccommodation)
909
910def addStudentAccommodation(container, id, REQUEST=None, **kw):
911    """Add a Students personal data."""
912    ob = StudentAccommodation(id, **kw)
913    return CPSBase_adder(container, ob, REQUEST=REQUEST)
914
915###)
916
917class StudentPersonal(CPSDocument): ###(
918    """
919    WAeUP Student container for the various student data
920    """
921    meta_type = 'StudentPersonal'
922    portal_type = meta_type
923    security = ClassSecurityInfo()
924
925    security.declareProtected(View,"Title")
926    def Title(self):
927        """compose title"""
928        content = self.getContent()
929        #return "Personal Data for %s %s" % (content.firstname,content.lastname)
930        return "Personal Data"
931
932
933InitializeClass(StudentPersonal)
934
935def addStudentPersonal(container, id, REQUEST=None, **kw):
936    """Add a Students personal data."""
937    ob = StudentPersonal(id, **kw)
938    return CPSBase_adder(container, ob, REQUEST=REQUEST)
939
940###)
941
942class StudentClearance(CPSDocument): ###(
943    """
944    WAeUP Student container for the various student data
945    """
946    meta_type = 'StudentClearance'
947    portal_type = meta_type
948    security = ClassSecurityInfo()
949
950    security.declareProtected(View,"Title")
951    def Title(self):
952        """compose title"""
953        content = self.getContent()
954        #return "Clearance/Eligibility Record for %s %s" % (content.firstname,content.lastname)
955        return "Clearance/Eligibility Record"
956
957
958InitializeClass(StudentClearance)
959
960def addStudentClearance(container, id, REQUEST=None, **kw):
961    """Add a Students personal data."""
962    ob = StudentClearance(id, **kw)
963    return CPSBase_adder(container, ob, REQUEST=REQUEST)
964
965###)
966
967class StudentStudyLevel(CPSDocument): ###(
968    """
969    WAeUP Student container for the various student data
970    """
971    meta_type = 'StudentStudyLevel'
972    portal_type = meta_type
973    security = ClassSecurityInfo()
974
975    security.declareProtected(View,"Title")
976    def Title(self):
977        """compose title"""
978        return "Level %s" % self.aq_parent.getId()
979
980##    security.declarePublic("gpa")
981##    def gpa(self):
982##        """calculate the gpa"""
983##        sum = 0
984##        course_count = 0
985##        for sc in self.objectValues():
986##            result = sc.getContent()
987##            if not result.grade:
988##                continue
989##            res = self.portal_catalog({'meta_type': 'Course',
990##                                          'id': sc.aq_parent.id})
991##            if len(res) != 1:
992##                continue
993##            course = res[0].getObject().getContent()
994##            sum += course.credits * ['F','E','D','C','B','A'].index(result.grade)
995##            course_count += 1
996##        if course_count:
997##            return sum/course_count
998##        return 0.0
999
1000InitializeClass(StudentStudyLevel)
1001
1002def addStudentStudyLevel(container, id, REQUEST=None, **kw):
1003    """Add a Students personal data."""
1004    ob = StudentStudyLevel(id, **kw)
1005    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1006
1007###)
1008
1009class StudentStudyCourse(CPSDocument): ###(
1010    """
1011    WAeUP Student container for the various student data
1012    """
1013    meta_type = 'StudentStudyCourse'
1014    portal_type = meta_type
1015    security = ClassSecurityInfo()
1016
1017    security.declareProtected(View,"Title")
1018    def Title(self):
1019        """compose title"""
1020        content = self.getContent()
1021        return "Study Course"
1022
1023
1024InitializeClass(StudentStudyCourse)
1025
1026def addStudentStudyCourse(container, id, REQUEST=None, **kw):
1027    """Add a Students personal data."""
1028    ob = StudentStudyCourse(id, **kw)
1029    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1030
1031###)
1032
1033class StudentApplication(CPSDocument): ###(
1034    """
1035    WAeUP Student container for the various student data
1036    """
1037    meta_type = 'StudentApplication'
1038    portal_type = meta_type
1039    security = ClassSecurityInfo()
1040
1041    security.declareProtected(View,"Title")
1042    def Title(self):
1043        """compose title"""
1044        return "Application Data"
1045
1046
1047InitializeClass(StudentApplication)
1048
1049def addStudentApplication(container, id, REQUEST=None, **kw):
1050    """Add a Students eligibility data."""
1051    ob = StudentApplication(id, **kw)
1052    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1053###)
1054
1055
1056class StudentPume(CPSDocument): ###(
1057    """
1058    WAeUP Student container for the various student data
1059    """
1060    meta_type = 'StudentPume'
1061    portal_type = meta_type
1062    security = ClassSecurityInfo()
1063
1064    security.declareProtected(View,"Title")
1065    def Title(self):
1066        """compose title"""
1067        return "PUME Results"
1068
1069
1070InitializeClass(StudentPume)
1071
1072def addStudentPume(container, id, REQUEST=None, **kw):
1073    """Add a Students PUME data."""
1074    ob = StudentPume(id, **kw)
1075    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1076###)
1077
1078##class StudentSemester(CPSDocument): ###(
1079##    """
1080##    WAeUP StudentSemester containing the courses and students
1081##    """
1082##    meta_type = 'StudentSemester'
1083##    portal_type = meta_type
1084##    security = ClassSecurityInfo()
1085##
1086##InitializeClass(StudentSemester)
1087##
1088##def addStudentSemester(container, id, REQUEST=None, **kw):
1089##    """Add a StudentSemester."""
1090##    ob = StudentSemester(id, **kw)
1091##    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1092##
1093#####)
1094
1095##class Semester(CPSDocument): ###(
1096##    """
1097##    WAeUP Semester containing the courses and students
1098##    """
1099##    meta_type = 'Semester'
1100##    portal_type = meta_type
1101##    security = ClassSecurityInfo()
1102##
1103##InitializeClass(Semester)
1104##
1105##def addSemester(container, id, REQUEST=None, **kw):
1106##    """Add a Semester."""
1107##    ob = Semester(id, **kw)
1108##    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1109##
1110#####)
1111
1112class StudentCourseResult(CPSDocument): ###(
1113    """
1114    WAeUP StudentCourseResult
1115    """
1116    meta_type = 'StudentCourseResult'
1117    portal_type = meta_type
1118    security = ClassSecurityInfo()
1119
1120    def getCourseEntry(self,cid):
1121        res = self.portal_catalog({'meta_type': "Course",
1122                                           'id': cid})
1123        if res:
1124            return res[-1]
1125        else:
1126            return None
1127
1128    security.declareProtected(View,"Title")
1129    def Title(self):
1130        """compose title"""
1131        cid = self.aq_parent.getId()
1132        ce = self.getCourseEntry(cid)
1133        if ce:
1134            return "%s" % ce.Title
1135        return "No course with id %s" % cid
1136
1137InitializeClass(StudentCourseResult)
1138
1139def addStudentCourseResult(container, id, REQUEST=None, **kw):
1140    """Add a StudentCourseResult."""
1141    ob = StudentCourseResult(id, **kw)
1142    return CPSBase_adder(container, ob, REQUEST=REQUEST)
1143###)
1144
1145# Backward Compatibility StudyLevel
1146
1147from Products.WAeUP_SRP.Academics import StudyLevel
1148
1149from Products.WAeUP_SRP.Academics import addStudyLevel
1150
Note: See TracBrowser for help on using the repository browser.