source: WAeUP_SRP/base/WAeUPImport.py @ 3293

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

implement #500

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