source: WAeUP_SRP/base/WAeUPImport.py @ 3321

Last change on this file since 3321 was 3320, checked in by Henrik Bettermann, 17 years ago

make import work

  • Property svn:keywords set to Id
File size: 48.0 KB
Line 
1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 The WAeUP group  <http://www.waeup.org>
3# Author: Joachim Schmitz (js@aixtraware.de)
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17# 02111-1307, USA.
18#
19# $Id: WAeUPImport.py 3320 2008-03-11 20:31:44Z henrik $
20"""The WAeUP Tool Box.
21"""
22
23#from AccessControl import ClassSecurityInfo
24#from Acquisition import aq_inner
25#from Acquisition import aq_parent
26#from Globals import DTMLFile
27#from Globals import InitializeClass
28from OFS.SimpleItem import SimpleItem
29from zExceptions import BadRequest
30
31#from Products.CMFCore.utils import getToolByName
32#from Products.CPSSchemas.DataStructure import DataStructure
33#from Products.CPSSchemas.DataModel import DataModel
34#from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
35from Products.CMFCore.ActionProviderBase import ActionProviderBase
36#from Products.CMFCore.permissions import View
37#from Products.ZCatalog.ZCatalog import ZCatalog
38#from Products.CMFCore.permissions import ModifyPortalContent
39#from Products.CMFCore.permissions import ManagePortal
40from Products.CMFCore.utils import UniqueObject
41#from Products.CMFCore.URLTool import URLTool
42from Products.CMFCore.utils import getToolByName
43from Globals import package_home,INSTANCE_HOME
44from Products.AdvancedQuery import Eq, Between, Le,In
45import csv,re,os,sys
46from shutil import copy2
47import DateTime,time
48import logging
49p_home = package_home(globals())
50i_home = INSTANCE_HOME
51from utils import makeDigest
52
53NO_KEY = '----'
54IGNORE = 'ignore'
55class WAeUPImport(UniqueObject, SimpleItem, ActionProviderBase): ###(
56    """ WAeUPImport """
57    required_modes = ('create',)
58
59    def __init__(self,waeup_tool): ###(
60        self.students_folder = waeup_tool.portal_url.getPortalObject().campus.students
61        self.member = member = waeup_tool.portal_membership.getAuthenticatedMember()
62        self.import_date = DateTime.DateTime()
63        self.imported_by = str(member)
64        #self.current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
65        self.waeup_tool = waeup_tool
66        self.academics_folder = waeup_tool.portal_url.getPortalObject().campus.academics
67        self.schema_tool = getToolByName(waeup_tool, 'portal_schemas')
68        self.layout_tool = getToolByName(waeup_tool, 'portal_layouts')
69        self.portal_workflow = getToolByName(waeup_tool, 'portal_workflow')
70        self.portal_url = getToolByName(waeup_tool, 'portal_url')
71        self.portal_catalog = waeup_tool.portal_catalog
72        self.students_catalog = waeup_tool.students_catalog
73        self.courses_catalog = waeup_tool.courses_catalog
74        self.course_results = waeup_tool.course_results
75        self.applicants_catalog = waeup_tool.applicants_catalog
76        #self.mode = mode
77        # self.import_method = getattr(self, '%s' % mode,None)
78        errors = []
79        # if self.import_method is None:
80        #     errors.append('No importer method %s' % mode)
81        self.pending_path = "%s/import/%s.pending" % (i_home,self.plural_name)
82        self.pending_tmp = "%s/import/%s.pending.tmp" % (i_home,self.plural_name)
83        self.pending_backup = "%s/import/%s.pending.old" % (i_home,self.plural_name)
84        self.pending_fn = os.path.split(self.pending_path)[1]
85        self.imported_path = "%s/import/%s.imported" % (i_home,self.plural_name)
86        self.imported_fn = os.path.split(self.imported_path)[1]
87        iname = "import_%s" % self.name
88        self.logger = logging.getLogger('WAeUPImport.%sImport' % self.plural_name.capitalize())
89        self.schema = self.schema_tool._getOb(iname,None)
90        #self.pending_schema = self.schema_tool._getOb("%s_pending" % iname,None)
91        self.layout = self.layout_tool._getOb(iname,None)
92        while True:
93            if self.schema is None:
94                errors.append('no schema %s' % iname)
95            # if self.pending_schema is None:
96            #     self.pending_schema = self.schema
97            if self.layout is None:
98                errors.append('no such layout %s' % iname)
99            if errors:
100                break
101            self.data_keys = self.schema.keys()
102            self.csv_keys = self.schema.keys()
103            info = {}
104            info['imported_from'] = ''
105            info['imported_by'] =  self.imported_by
106            info['import_date'] = self.import_date.strftime("%d/%m/%y %H:%M:%S")
107            info['error'] = ''
108            self.info = info
109            self.csv_keys.extend(self.info)
110            self.validators = {}
111            for widget in self.layout.keys():
112                self.validators[widget] = self.layout[widget].validate
113            self.required_keys = {}
114            for mode in self.required_modes:
115                self.required_keys[mode] = [self.layout.getIdUnprefixed(id)
116                                    for id,widget in self.layout.objectItems()
117                                    if widget.is_required]
118            break
119        self.init_errors = ','.join(errors)
120    ###)
121
122    def makeIdLists(self): ###(
123        pending_digests = []
124        pending = []
125        # pending_student_ids = []
126        # pending_matric_nos = []
127        # pending_reg_ns = []
128        if os.path.exists(self.pending_path):
129            datafile = open(self.pending_path,"r")
130            pending_csv_reader = csv.DictReader(datafile,self.csv_keys,)
131            pending_csv_reader.next() # skip headline
132            for item in pending_csv_reader:
133                digest = makeDigest(item,self.data_keys)
134                if digest not in pending_digests:
135                    pending_digests += digest,
136                    pending += item,
137            datafile.close()
138            #copy2(self.pending_path,self.pending_backup)
139        return pending, pending_digests
140    ###)
141
142    def checkHeadline(self,headline): ###(
143        """ check the headline of a csv file """
144        import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
145                                                        or k.strip() in self.info.keys())]
146        # import_keys = [k.strip() for k in headline if not (k.strip() in self.info.keys())]
147        diff2schema = set(import_keys).difference(set(self.schema.keys()))
148        diff2layout = set(import_keys).difference(set(self.layout.keys()))
149        #if diff2schema and diff2schema != set(['id',]):
150        if diff2schema:
151            return list(diff2schema)
152        return []
153    ###)
154
155    def getHeadlineFields(self,headline,values): ###(
156        """ check the headline of a csv file """
157        # import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
158        #                                                 or k.strip() in self.info.keys())]
159        import_keys = [k.strip() for k in headline if not (k.strip() in self.info.keys())]
160        si = set(import_keys)
161        ss = set(self.schema.keys())
162
163        invalid_keys = si - ss
164        keys = []
165        i = 0
166        duplicates = False
167        singels = []
168        msg = ''
169        while True:
170            if len(values) != len(import_keys):
171                msg += "+ %d fields in headline but %d values +" % (len(import_keys),len(values))
172                break
173            for k in import_keys:
174                if k in singels:
175                    keys += (k,'%s' % k,values[i],'(duplicate)'),
176                    msg += ("+ duplicate %s +" % k)
177                    keys[singels.index(k)] = (k,'%s' % k,values[singels.index(k)],'(duplicate)')
178                elif k in invalid_keys and not k.startswith(IGNORE):
179                    keys += (k,NO_KEY,values[i],'(invalid)'),
180                else:
181                    keys += (k,k,values[i],''),
182                i += 1
183                singels += k,
184            break
185        return msg,keys
186    ###)
187###)
188
189
190class ApplicationImport(WAeUPImport):###(
191    name = "application"
192    plural_name = "%ss" % name
193    commit_after = 1000
194
195    def create(self,mapping):###(
196        reg_no = mapping.get('reg_no')
197        msg = ''
198        while True:
199            try:
200                self.applicants_catalog.addRecord(**mapping)
201            except ValueError:
202                msg =  "applicant record with reg_no %s already exists" % reg_no
203            break
204        return reg_no,msg,mapping
205    ###)
206
207    def edit(self,mapping):###(
208        reg_no = mapping.get('reg_no')
209        status = mapping.get('status')
210        msg = ''
211        while True:
212            res = self.applicants_catalog(reg_no = reg_no)
213            if len(res):
214                if res[0].status == 'created' and status != 'created':
215                    msg =  "student object with id %s for %s already created, status cannot be changed" % (res[0].student_id, reg_no)
216                elif status == 'created' and res[0].status != 'created':
217                    msg =  "student object for %s has not yet been created, status cannot be set to 'created'" % (reg_no)
218                else:
219                    self.applicants_catalog.modifyRecord(**mapping)
220            else:
221                msg =  "applicant record with reg_no %s does not exist" % reg_no
222            break
223        return reg_no,msg,mapping
224    ###)
225
226###)
227
228class CertificateImport(WAeUPImport):###(
229    name = "certificate"
230    plural_name = "%ss" % name
231    commit_after = 100000
232
233    def create(self,mapping):###(
234        if getattr(self,'_v_certificate_list',None) is None:
235            self._v_certificate_list = []
236        if getattr(self,'_v_department_certificates',None) is None:
237            departments = self.portal_catalog(portal_type = "Department")
238            self._v_department_certificates = {}
239            for d in departments:
240                certificates_folder = getattr(d.getObject(),"certificates",None)
241                self._v_department_certificates[d.getId] = certificates_folder.objectIds()
242        department_id = mapping['department_code']
243        msg = ''
244        certificate_id = mapping.get('code')
245        while True:
246            department_certificates = self._v_department_certificates.get(department_id,None)
247            if department_certificates is None:
248                msg =  "No Department with ID: %s" % department_id
249                break
250            if certificate_id in self._v_certificate_list:
251                msg =  "Duplicate Certificate ID: %s" % department_id
252                break
253            if certificate_id in department_certificates:
254                msg =  "Duplicate Certificate ID: %s" % department_id
255                break
256            try:
257                d.invokeFactory('Certificate', certificate_id)
258            except BadRequest,E:
259                msg =  "%s" % E
260                break
261            self._v_certificate_list.append(certificate_id)
262            c = getattr(d,certificate_id)
263            c.getContent().edit(mapping=mapping)
264            break
265        return certificate_id,msg,mapping
266    ###)
267
268    def edit(self,mapping):###(
269        certificate_id = mapping.get('code')
270        res = self.portal_catalog(id=certificate_id)
271        msg = ''
272        while True:
273            if not res:
274                msg =  "no certificate with id: %s" % certificate_id
275                break
276            c = res[0].getObject()
277            c.getContent().edit(mapping=mapping)
278            break
279        return certificate_id,msg,mapping
280    ###)
281###)
282
283class CourseImport(WAeUPImport):###(
284    name = "course"
285    plural_name = "%ss" % name
286    commit_after = 1000
287
288    def create(self,mapping):###(
289        if getattr(self,'_v_course_list',None) is None:
290            self._v_course_list = []
291        if getattr(self,'_v_department_courses',None) is None:
292            departments = self.portal_catalog(portal_type = "Department")
293            self._v_department_courses = {}
294            for department in departments:
295                courses_folder = getattr(department.getObject(),"courses",None)
296                if courses_folder is not None:
297                    self._v_department_courses[department.getId] = courses_folder.objectIds()
298        department_id = mapping['department_code']
299        course_id = mapping.get('code','')
300        msg = ''
301        while True:
302            department_courses = self._v_department_courses.get(department_id,None)
303            if department_courses is None:
304                msg =  "no department with id: %(department_id)s" % vars()
305                break
306            if course_id in self._v_course_list:
307                msg =  "duplicate course id: %(course_id)s" % vars()
308                break
309            if course_id in department_courses:
310                msg =  "course %(course_id)s already exists in department %(department_id)s" % vars()
311                break
312            try:
313                department.invokeFactory('Course', course_id)
314            except BadRequest,E:
315                msg =  "%s" % E
316                break
317            self._v_course_list.append(course_id)
318            course = getattr(department,course_id)
319            course.getContent().edit(mapping=mapping)
320            break
321        return course_id,msg,mapping
322    ###)
323
324    def edit(self,mapping): ###(
325        course_id = mapping.get('code','')
326        course = self.courses_catalog.getRecordByKey(course_id)
327        while True:
328            if course is None:
329                msg =  "no course with id: %s" % course_id
330                break
331            course_object = getattr(getattr(self.academics_folder,course.department),course_id)
332            course_object.getContent().edit(mapping=mapping)
333            break
334        return course_id,msg,mapping
335    ###)
336###)
337
338class CourseResultImport(WAeUPImport):###(
339    """ CourseresultImport """
340    name = "course_result"
341    plural_name = "%ss" % name
342    commit_after = 1000000
343    required_modes = ('create','edit','remove')
344
345    def getStudentRecord(self,mapping): ###(
346        id_field_found = False
347        msg = ''
348        student_record = None
349        id_count = 0
350        for id_key in ('id','matric_no'):
351            id_field = mapping.get(id_key,'')
352            if id_field:
353                id_count += 1
354                search_key = id_key
355                search_field = id_field
356        while True:
357            if id_count > 1:
358                msg = "both id and matric_no are provided"
359                break
360            elif id_count == 0:
361                msg = "neither id nor matric_no provided"
362                break
363            query = Eq(search_key,search_field)
364            res = self.students_catalog.evalAdvancedQuery(query)
365            if res:
366                student_record = res[0]
367                if search_key == "matric_no":
368                    mapping['id'] = student_record.id
369                elif search_key == "id":
370                    mapping['matric_no'] = student_record.matric_no
371            else:
372                msg = "no student with %(search_key)s %(search_field)s" % vars()
373            break
374        return student_record,msg
375    ###)
376
377    def create(self,mapping):###(
378        students_folder = self.portal_url.getPortalObject().campus.students
379        if getattr(self,'_v_courses',None) is None:
380            res = self.courses_catalog()
381            self._v_courses = {}
382            for brain in res:
383                self._v_courses[brain.code] = brain
384        if getattr(self,'_v_level_created',None) is None:
385            self._v_level_created = []
386        msg = ''
387        key = ''
388        while True:
389            course_id = mapping.get('code')
390            if course_id not in self._v_courses.keys():
391                msg = "no course with id: %s" % course_id
392                break
393            student_record,msg = self.getStudentRecord(mapping)
394            if msg:
395                break
396            student_id = student_record.id
397            level_id = mapping.get('level_id','')
398            code = mapping.get('code','')
399            if student_id not in self._v_level_created:
400                try:
401                    context = getattr(getattr(students_folder,
402                                            "%(student_id)s" % vars()),
403                                    'study_course')
404                except:
405                    msg = "could not create level %(level_id)s for %(student_id)s" % vars()
406                    break
407                if level_id not in context.objectIds():
408                    context.invokeFactory('StudentStudyLevel',"%(level_id)s" % vars())
409                    level = getattr(context,"%(level_id)s" % vars())
410                    self.portal_workflow.doActionFor(level,'open')
411                    # the session string must not be copied into the level object
412                    current_verdict = getattr(student_record,'current_verdict','')
413                    current_session = getattr(student_record,'current_session','')
414                    if current_verdict and student_record.current_level == level_id:
415                        level.getContent().edit(mapping={'verdict': "%s" %
416                                                        current_verdict,
417                                                        'session': "%s" %
418                                                        current_session,
419                                                        })
420                        self.portal_workflow.doActionFor(level,'close')
421                self._v_level_created += student_id,
422            mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
423            for k in ('semester','credits',):
424                mapping[k] = getattr(self._v_courses[course_id],k)
425            try:
426                self.course_results.addRecord(**mapping)
427            except ValueError:
428                msg = "course result already exists: %s" % key
429            break
430        return key,msg,mapping
431    ###)
432
433    def edit(self,mapping): ###(
434        msg = ''
435        key = ''
436        while True:
437            student_record,msg = self.getStudentRecord(mapping)
438            if msg:
439                break
440            level_id = mapping.get('level_id','')
441            code = mapping.get('code','')
442            code = mapping['code']
443            mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
444            break
445        try:
446            self.course_results.modifyRecord(**mapping)
447        except KeyError:
448            msg = "no course result with key %s" % key
449        return key,msg,mapping
450    ###)
451
452    def remove(self,mapping):###(
453        key = ''
454        msg = ''
455        while True:
456            student_record,msg = self.getStudentRecord(mapping)
457            if msg:
458                break
459            student_id = student_record.id
460            level_id = mapping.get('level_id','')
461            code = mapping.get('code','')
462            key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
463            if self.course_results.getRecordByKey(key) is None:
464                msg =  "no course result with key %(key)s" % vars()
465                break
466            self.course_results.deleteRecord(key)
467            break
468        return key,msg,mapping
469    ###)
470
471###)
472
473class CertificateCourseImport(WAeUPImport):###(
474    name = "certificate_course"
475    plural_name = "%ss" % name
476    commit_after = 100000
477    required_modes = ('create','edit')
478
479    def create(self,mapping):
480        if getattr(self,'_v_courses',None) is None:
481            res = self.courses_catalog()
482            self._v_courses= [course.code for course in res]
483        if getattr(self,'_v_ceritficates',None) is None:
484            res = self.portal_catalog(portal_type = "Certificate")
485            self._v_certificates = {}
486            for cert in res:
487                self._v_certificates[cert.getId] = cert.getObject()
488        msg = ''
489        while True:
490            certificate_course_id = mapping.get('code')
491            if certificate_course_id not in self._v_courses:
492                msg =  "no course with id: %s" % certificate_course_id
493                break
494            cert_id = mapping['certificate_code']
495            cert = self._v_certificates.get(cert_id,None)
496            if cert is None:
497                msg =  "no certificate with id: %s" % cert_id
498                break
499            level_id = mapping.get('level')
500            level = getattr(cert,level_id,None)
501            if level is None:
502                cert.invokeFactory('StudyLevel', level_id)
503                level = getattr(cert,level_id,None)
504            elif hasattr(level,certificate_course_id):
505                msg =  "duplicate certificate course id: %(certificate_course_id)s " % vars()
506                msg += "in %(cert_id)s/ %(level_id)s" % vars()
507                break
508            level.invokeFactory('CertificateCourse', certificate_course_id)
509            c = getattr(level,certificate_course_id)
510            c.getContent().edit(mapping=mapping)
511            break
512        return certificate_course_id,msg,mapping
513    ###)
514
515class DepartmentImport(WAeUPImport):###(
516    name = "department"
517    plural_name = "%ss" % name
518    commit_after = 1000
519
520    def create(self,mapping):###(
521        "create a department in the correct faculty"
522        faculty_id = mapping['faculty_code']
523        msg = ''
524        if getattr(self,'_v_faculties',None) is None:
525            res = self.portal_catalog(portal_type = "Department")
526            self._v_faculties = {}
527            for f in res:
528                self._v_faculties[f.getId] = f.getObject()
529        department_id = mapping.get('code','')
530        while True:
531            faculty = self._v_faculties.get(faculty_id,None)
532            if faculty is None:
533                msg =  "no faculty with id: %s" % faculty_id
534                break
535            else:
536                d = getattr(faculty,department_id,None)
537                if d is None or d.portal_type == "Faculty":
538                    try:
539                        faculty.invokeFactory('Department', department_id)
540                    except BadRequest,E:
541                        msg =  "%s" % E
542                        break
543                    d = getattr(faculty,department_id)
544                    d.invokeFactory('CoursesFolder','courses')
545                    courses = getattr(d,'courses')
546                    dict = {'Title': 'Courses'}
547                    courses.getContent().edit(mapping=dict)
548                    d.invokeFactory('CertificatesFolder','certificates')
549                    certificates = getattr(d,'certificates')
550                    dict = {'Title': 'Certificates'}
551                    certificates.getContent().edit(mapping=dict)
552                    d.getContent().edit(mapping=mapping)
553            break
554        return department_id,msg,mapping
555    ###)
556
557    def edit(self,mapping): ###(
558        "edit a department in the correct faculty"
559        academics_folder = self.portal_url.getPortalObject().campus.academics
560        faculty_id = mapping['faculty_code']
561        department_id = mapping.get('code','')
562        msg = ''
563        while True:
564            try:
565                d = getattr(getattr(academics_folder,faculty_id),department_id,None)
566            except KeyError:
567                msg =  "department %s or faculty %s wrong" % (department_id,faculty_id)
568                break
569            if d is None or d.portal_type == "Faculty":
570                msg =  "department %s not found" % (department_id)
571                break
572            d.getContent().edit(mapping=mapping)
573            break
574        return department_id,msg,mapping
575    ###)
576###)
577
578class FacultyImport(WAeUPImport):###(
579    name = "faculty"
580    plural_name = "faculties"
581    commit_after = 100
582
583    def create(self,mapping): ###(
584        "create a faculty"
585        academics_folder = self.portal_url.getPortalObject().campus.academics
586        faculty_id = mapping.get('code','')
587        msg = ''
588        while True:
589            if faculty_id in academics_folder.objectIds():
590                msg =  "faculty with id: %s exists" % faculty_id
591                break
592            logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
593            try:
594                academics_folder.invokeFactory('Faculty', faculty_id)
595            except BadRequest,E:
596                msg =  "%s" % E
597                break
598            f = getattr(academics_folder,faculty_id,None)
599            f.getContent().edit(mapping=mapping)
600            break
601        return faculty_id,msg,mapping
602        ###)
603
604    def edit(self,mapping): ###(
605        "edit a faculty"
606        academics_folder = self.portal_url.getPortalObject().campus.academics
607        faculty_id = mapping['code']
608        msg = ''
609        while True:
610            f = getattr(academics_folder,faculty_id,None)
611            if f is None:
612                msg =  "faculty with id: %s does not exist" % faculty_id
613            f.getContent().edit(mapping=mapping)
614            break
615        return faculty_id,msg,mapping
616    ###)
617###)
618
619class StudentImport(WAeUPImport):###(
620    name = "student"
621    plural_name = "%ss" % name
622    commit_after = 100
623
624    field2types_student = {   ###(
625                      'StudentApplication':
626                          {'id': 'application',
627                           'title': 'Application Data',
628                           'wf_transition_return': 'close',
629                           'wf_transition_admit': 'remain',
630                           'fields':
631                             ('jamb_reg_no',
632                              'entry_mode',
633                              'entry_session',
634                              'jamb_score',
635                              'app_email',
636                              'jamb_age',
637                              'jamb_state',
638                              'jamb_lga',
639                              'jamb_sex',
640                              )
641                              },
642                      #'StudentPume':
643                      #    {'id': 'pume',
644                      #     'title': 'Pume Data',
645                      #     'wf_transition_return': 'close',
646                      #     'wf_transition_admit': 'close',
647                      #     'fields':
648                      #       ('pume_score',
649                      #        )
650                      #        },
651                      'StudentClearance':
652                          {'id': 'clearance',
653                           'title': 'Clearance/Eligibility Record',
654                           'wf_transition_return': 'close',
655                           'wf_transition_admit': 'remain',
656                           'fields':
657                             ('matric_no',
658                              'nationality',
659                              'lga',
660                              'birthday',
661                              )
662                              },
663                         'StudentPersonal':
664                          {'id': 'personal',
665                           'title': 'Personal Data',
666                           'wf_transition_return': 'open',
667                           'wf_transition_admit': 'remain',
668                           'fields':
669                             ('firstname',
670                              'middlename',
671                              'lastname',
672                              'sex',
673                              'email',
674                              'phone',
675                              'perm_address',
676                              )
677                              },
678                         'StudentStudyCourse':
679                          {'id': 'study_course',
680                           'title': 'Study Course',
681                           'wf_transition_return': 'open',
682                           'wf_transition_admit': 'remain',
683                           'fields':
684                             ('study_course',
685                              'current_level',
686                              'current_session',
687                              'current_mode',
688                              'current_verdict',
689                              'previous_verdict',
690                              )
691                              },
692                         # 'StudentStudyLevel':
693                         #  {'id': 'current_level',
694                         #   'title': '',
695                         #   'wf_transition_return': 'open',
696                         #   'wf_transition_admit': 'remain',
697                         #   'fields':
698                         #     ('verdict',
699                         #      'session',
700                         #      )
701                         #      },
702                         'PaymentsFolder':
703                          {'id': 'payments',
704                           'title': 'Payments',
705                           'wf_transition_return': 'open',
706                           'wf_transition_admit': 'open',
707                           'fields':
708                             ()
709                              },
710                         }
711    ###)
712
713    def create(self,mapping): ###(
714        "create student records due import"
715        logger = logging.getLogger('WAeUPTool.mass_create_student')
716        students_folder = self.portal_url.getPortalObject().campus.students
717        jamb_reg_no = mapping.get('jamb_reg_no',None)
718        matric_no = mapping.get('matric_no',None)
719        msg = ''
720        student_id = mapping.get('id',None)
721        while True:
722            if student_id:
723                msg = "student_id must not be specified in create mode"
724                break
725            if jamb_reg_no:
726                res = self.students_catalog(jamb_reg_no = jamb_reg_no)
727                if res:
728                    msg = "jamb_reg_no exists"
729                    break
730            if matric_no:
731                res = self.students_catalog(matric_no = matric_no)
732                if res:
733                    msg = "matric_no exists"
734                    break
735            if not matric_no and not jamb_reg_no:
736                msg = "jamb_reg_no or matric_no must be specified"
737                break
738            student_id = self.waeup_tool.generateStudentId('?')
739            students_folder.invokeFactory('Student', student_id)
740            student_obj = getattr(students_folder,student_id)
741            f2t = self.field2types_student
742            d = {}
743            transition = mapping.get('reg_transition','admit')
744            if transition not in ('admit','return'):
745                msg = "no valid transition provided"
746                break
747            for pt in f2t.keys():
748                student_obj.invokeFactory(pt,f2t[pt]['id'])
749                sub_obj = getattr(student_obj,f2t[pt]['id'])
750                sub_doc = sub_obj.getContent()
751                d['Title'] = f2t[pt]['title']
752                for field in f2t[pt]['fields']:
753                    d[field] = mapping.get(field,'')
754
755                if pt == "StudentApplication":
756                    #d['jamb_sex']  = 'M'
757                    #if mapping.get('sex'):
758                    #    d['jamb_sex']  = 'F'
759                    d['jamb_firstname'] = mapping.get('firstname',None)
760                    d['jamb_middlename'] = mapping.get('middlename',None)
761                    d['jamb_lastname'] = mapping.get('lastname',None)
762
763                # if pt == "StudyCourse":
764                #     for von,zu in (('entry_mode','current_mode'),
765                #                    ('entry_session','current_session')):
766                #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
767                #             d[zu] = mapping[von]
768                sub_doc.edit(mapping = d)
769
770                #import pdb;pdb.set_trace()
771                new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
772                if new_state != "remain":
773                    self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
774            self.portal_workflow.doActionFor(student_obj,transition)
775            student_obj.manage_setLocalRoles(student_id, ['Owner',])
776            mapping['id'] = student_id
777            break
778        return student_id,msg,mapping
779    ###)
780
781    def edit(self,mapping): ###(
782        wftool = self.portal_workflow
783        "edit student records due import"
784        logger = logging.getLogger('WAeUPTool.mass_edit_student')
785        students_folder = self.portal_url.getPortalObject().campus.students
786        student_id = mapping.get('id',None)
787        jamb_reg_no = mapping.get('jamb_reg_no',None)
788        matric_no = mapping.get('matric_no',None)
789        editable_keys = mapping.keys()
790        msg = ''
791        while True:
792            if student_id:
793                res = self.students_catalog(id = student_id)
794                if not res:
795                    msg = "no student with id %s" % student_id
796                    break
797                student_record = res[0]
798                if matric_no and student_record.matric_no:
799                    if  matric_no != student_record.matric_no:
800                        msg = "old matric_no %s overwritten with %s" % (student_record.matric_no,matric_no)
801                        #logger.info("%s, old matric_no %s overwritten with %s" % (student_record.id,student_record.matric_no,matric_no))
802                if jamb_reg_no and student_record.jamb_reg_no:
803                    if jamb_reg_no != student_record.jamb_reg_no:
804                        msg = "old reg_no %s overwritten with %s" % (student_record.jamb_reg_no,jamb_reg_no)
805                        #logger.info("%s, old reg_no %s overwritten with %s" % (student_record.id,student_record.jamb_reg_no,jamb_reg_no))
806            elif jamb_reg_no:
807                res = self.students_catalog(jamb_reg_no = jamb_reg_no)
808                if not res:
809                    msg = "no student with jamb_reg_no %s" % jamb_reg_no
810                    break
811                student_record = res[0]
812                editable_keys.remove('jamb_reg_no')
813            elif matric_no:
814                res = self.students_catalog(matric_no = matric_no)
815                if not res:
816                    msg = "no student with matric_no %s" % matric_no
817                    break
818                student_record = res[0]
819                editable_keys.remove('matric_no')
820            ## included only to change wf state from admitted to returning
821            #if student_record.review_state not in ('admitted','objection_raised'):
822            #    return '%s' % student_record.id ,"student is not in state admitted or objection_raised"
823            ## end inclusion
824            student_id = student_record.id
825            student_obj = getattr(students_folder,student_id)
826            f2t = self.field2types_student
827            d = {}
828            any_change = False
829            #special treatment for StudentStudyLevel
830            d['verdict']  = mapping.get('current_verdict','')
831            d['session']  = mapping.get('current_session','')
832            current_level = mapping.get('current_level','')
833            while d['session'] and d['verdict'] and current_level:
834                sub_obj = getattr(student_obj,'study_course',None)
835                if sub_obj is None:
836                    break
837                level_obj = getattr(sub_obj,current_level,None)
838                if  level_obj is None:
839                    break
840                any_change = True
841                level_obj.getContent().edit(mapping = d)
842                try:
843                    wftool.doActionFor(level_obj,'close')
844                except:
845                    pass
846                break
847            for pt in f2t.keys():
848                #if pt == "StudentApplication":
849                #    d['jamb_sex']  = 'M'
850                #    if mapping.get('sex'):
851                #        d['jamb_sex']  = 'F'
852                intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
853                if intersect and pt not in ('StudentStudyLevel',):
854                    object_id = f2t[pt]['id']
855                    sub_obj = getattr(student_obj,object_id,None)
856                    if sub_obj is None:
857                        try:
858                            student_obj.invokeFactory(pt,object_id)
859                        except:
860                            continue
861                        sub_obj = getattr(student_obj,object_id)
862                        if f2t[pt]['title'] != '':
863                            d['Title'] = f2t[pt]['title']
864                    sub_doc = sub_obj.getContent()
865                    for field in intersect:
866                        changed = False
867                        if getattr(sub_doc,field,None) != mapping.get(field,''):
868                            any_change = True
869                            changed = True
870                            d[field] = mapping.get(field,'')
871                        if changed:
872                            sub_doc.edit(mapping = d)
873            ## included only to change wf state from admitted to returning
874            #    if student_record.review_state in ('admitted','objection_raised'):
875            #        new_state = f2t[pt]['wf_transition_return']
876            #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
877            #        if sub_obj and new_state != "remain":
878            #            try:
879            #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
880            #            except:
881            #                #logger.info('%s, wf transition %s of %s failed' % (student_id,new_state,sub_obj.id))
882            #                pass
883            #if student_record.review_state in ('admitted','objection_raised'):
884            #    wfaction = 'return'
885            #    try:
886            #        self.portal_workflow.doActionFor(student_obj,wfaction)
887            #        logger.info('%s, wf state changed' % student_id)
888            #        any_change = True
889            #    except:
890            #        logger.info('%s, wf transition failed, old state = %s' % (student_id,student_record.review_state))
891            #        pass
892            ## end inclusion
893            break
894        # if not any_change:
895        #     msg = 'not modified'
896        return student_id,msg,mapping
897    ###)
898###)
899
900class VerdictImport(WAeUPImport):###(
901    """ VerdictImport """
902    name = "verdict"
903    plural_name = "%ss" % name
904    commit_after = 100000
905    required_modes = ('create','edit')
906
907    def create(self,mapping):
908        "edit student verdicts and create StudentStudyLevel object if not existent"
909        wftool = self.portal_workflow
910        logger = logging.getLogger('WAeUPTool.mass_edit_verdict')
911        students_folder = self.portal_url.getPortalObject().campus.students
912        student_id = mapping.get('id',None)
913        matric_no = mapping.get('matric_no',None)
914        editable_keys = mapping.keys()
915        while True:
916            key = ''
917            msg = ''
918            if student_id:
919                student_record = self.students_catalog.getRecordByKey(student_id)
920                if student_record is None:
921                    #return '',"no student with id %s" % student_id
922                    msg = "no student with id %s" % student_id
923                    break
924                if matric_no and student_record.matric_no and matric_no != student_record.matric_no:
925                    msg = 'student %s: matric_no %s does not match %s' % (student_record.id,
926                                                                          student_record.matric_no,
927                                                                          matric_no)
928                    break
929                mapping['matric_no'] = student_record.matric_no
930            elif matric_no:
931                res = self.students_catalog(matric_no = matric_no)
932                if not res:
933                    msg = "no student with matric_no %s" % matric_no
934                    break
935                student_record = res[0]
936                editable_keys.remove('matric_no')
937            else:
938                msg = "no id or matric_no specified"
939                break
940            student_id = student_record.id
941            mapping['id'] = student_id
942            d = {}
943            #import pdb;pdb.set_trace()
944            any_change = False
945            #special treatment for StudentStudyLevel
946            current_session = d['session'] = mapping.get('current_session','')
947            if current_session and student_record.session != current_session:
948                msg = 'student %s: imported session %s does not match current_session %s' % (student_id,
949                                                                                            current_session,
950                                                                                            student_record.session)
951                break
952            current_level = mapping.get('current_level','')
953            if not current_level.isdigit():
954                msg = 'student %s: imported level is empty' % (student_id,)
955                break
956            if current_level and student_record.level != current_level:
957                msg = 'student %s: imported level %s does not match current_level %s' % (student_id,
958                                                                                        current_level,
959                                                                                        student_record.level)
960                break
961            student_review_state =  student_record.review_state
962            if student_review_state == 'deactivated':
963                msg = "student %s in review_state %s" % (student_id, student_review_state)
964                break
965            if student_review_state not in ('courses_validated','returning'):
966                msg = "student %s in wrong review_state %s" % (student_id, student_review_state)
967                break
968            student_obj = getattr(students_folder,student_id)
969            # f2t = self.field2types_student
970            study_course_obj = getattr(student_obj,'study_course',None)
971            if study_course_obj is None:
972                msg = 'student %s: no study_course object' % student_id
973                break
974            level_obj = getattr(study_course_obj,current_level,None)
975
976            if  level_obj is None:
977                # The only difference to the edit method is that we create a StudentStudyLevel object
978                try:
979                    study_course_obj.invokeFactory('StudentStudyLevel',"%s" % current_level)
980                    level_obj = getattr(context,"%s" % current_level)
981                    level_obj.portal_workflow.doActionFor(level,'open')
982                except:
983                    continue
984                #msg = 'student %s: no study_level object for level %s' % (student_id,
985                #                                                                current_level)
986                #break
987
988            verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
989
990            #if verdict == student_record.verdict:
991            #    msg = 'student %s: verdict already set to %s' % (student_id,
992            #                                                            verdict)
993
994            level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
995            if level_review_state != "closed":
996                wftool.doActionFor(level_obj,'close')
997                # msg = 'student %s: level %s is not closed' % (student_id,
998                #                                                      current_level)
999
1000            study_course_obj.getContent().edit(mapping = d)
1001            level_obj.getContent().edit(mapping = d)
1002            if student_review_state != "returning":
1003                wftool.doActionFor(student_obj,'return')
1004            # try:
1005            #     wftool.doActionFor(level_obj,'close')
1006            # except:
1007            #     pass
1008            break
1009        return student_id,msg,mapping
1010
1011
1012    def edit(self,mapping):
1013        "edit student verdicts"
1014        wftool = self.portal_workflow
1015        logger = logging.getLogger('WAeUPTool.mass_edit_verdict')
1016        students_folder = self.portal_url.getPortalObject().campus.students
1017        student_id = mapping.get('id',None)
1018        matric_no = mapping.get('matric_no',None)
1019        editable_keys = mapping.keys()
1020        while True:
1021            key = ''
1022            msg = ''
1023            if student_id:
1024                student_record = self.students_catalog.getRecordByKey(student_id)
1025                if student_record is None:
1026                    #return '',"no student with id %s" % student_id
1027                    msg = "no student with id %s" % student_id
1028                    break
1029                if matric_no and student_record.matric_no and matric_no != student_record.matric_no:
1030                    msg = 'student %s: matric_no %s does not match %s' % (student_record.id,
1031                                                                          student_record.matric_no,
1032                                                                          matric_no)
1033                    break
1034                mapping['matric_no'] = student_record.matric_no
1035            elif matric_no:
1036                res = self.students_catalog(matric_no = matric_no)
1037                if not res:
1038                    msg = "no student with matric_no %s" % matric_no
1039                    break
1040                student_record = res[0]
1041                editable_keys.remove('matric_no')
1042            else:
1043                msg = "no id or matric_no specified"
1044                break
1045            student_id = student_record.id
1046            mapping['id'] = student_id
1047            d = {}
1048            #import pdb;pdb.set_trace()
1049            any_change = False
1050            #special treatment for StudentStudyLevel
1051            current_session = d['session'] = mapping.get('current_session','')
1052            if current_session and student_record.session != current_session:
1053                msg = 'student %s: imported session %s does not match current_session %s' % (student_id,
1054                                                                                            current_session,
1055                                                                                            student_record.session)
1056                break
1057            current_level = mapping.get('current_level','')
1058            if not current_level.isdigit():
1059                msg = 'student %s: imported level is empty' % (student_id,)
1060                break
1061            if current_level and student_record.level != current_level:
1062                msg = 'student %s: imported level %s does not match current_level %s' % (student_id,
1063                                                                                        current_level,
1064                                                                                        student_record.level)
1065                break
1066            student_review_state =  student_record.review_state
1067            if student_review_state == 'deactivated':
1068                msg = "student %s in review_state %s" % (student_id, student_review_state)
1069                break
1070            if student_review_state not in ('courses_validated','returning'):
1071                msg = "student %s in wrong review_state %s" % (student_id, student_review_state)
1072                break
1073            student_obj = getattr(students_folder,student_id)
1074            # f2t = self.field2types_student
1075            study_course_obj = getattr(student_obj,'study_course',None)
1076            if study_course_obj is None:
1077                msg = 'student %s: no study_course object' % student_id
1078                break
1079            level_obj = getattr(study_course_obj,current_level,None)
1080            if  level_obj is None:
1081                msg = 'student %s: no study_level object for level %s' % (student_id,
1082                                                                                current_level)
1083                break
1084            verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
1085
1086            #if verdict == student_record.verdict:
1087            #    msg = 'student %s: verdict already set to %s' % (student_id,
1088            #                                                            verdict)
1089
1090            level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
1091            if level_review_state != "closed":
1092                wftool.doActionFor(level_obj,'close')
1093                # msg = 'student %s: level %s is not closed' % (student_id,
1094                #                                                      current_level)
1095
1096            study_course_obj.getContent().edit(mapping = d)
1097            level_obj.getContent().edit(mapping = d)
1098            if student_review_state != "returning":
1099                wftool.doActionFor(student_obj,'return')
1100            # try:
1101            #     wftool.doActionFor(level_obj,'close')
1102            # except:
1103            #     pass
1104            break
1105        return student_id,msg,mapping
1106    ###)
1107
Note: See TracBrowser for help on using the repository browser.