source: WAeUP_SRP/base/WAeUPImport.py @ 3319

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

further improvements: error strings are now seperated by '+'

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