source: WAeUP_SRP/base/WAeUPImport.py @ 3358

Last change on this file since 3358 was 3355, checked in by joachim, 17 years ago

fix for #111 fceokene

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