source: WAeUP_SRP/base/WAeUPImport.py @ 3314

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

show all fields for editing with value from first record,
show one line per field for better readability
add edit again button for importable files.

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