source: WAeUP_SRP/base/WAeUPImport.py @ 3342

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

don't check for duplicate identifier

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