source: WAeUP_SRP/trunk/WAeUPImport.py @ 17347

Last change on this file since 17347 was 9233, checked in by Henrik Bettermann, 12 years ago

We do not need to remove the catalog entry.

  • Property svn:keywords set to Id
File size: 69.6 KB
RevLine 
[3172]1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 The WAeUP group  <http://www.waeup.org>
3# Author: Joachim Schmitz (js@aixtraware.de)
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17# 02111-1307, USA.
18#
19# $Id: WAeUPImport.py 9233 2012-09-26 04:11:16Z henrik $
20"""The WAeUP Tool Box.
21"""
22
23#from AccessControl import ClassSecurityInfo
24#from Acquisition import aq_inner
25#from Acquisition import aq_parent
26#from Globals import DTMLFile
27#from Globals import InitializeClass
[3277]28from OFS.SimpleItem import SimpleItem
[3172]29from zExceptions import BadRequest
30
31#from Products.CMFCore.utils import getToolByName
32#from Products.CPSSchemas.DataStructure import DataStructure
33#from Products.CPSSchemas.DataModel import DataModel
34#from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
[3277]35from Products.CMFCore.ActionProviderBase import ActionProviderBase
[3172]36#from Products.CMFCore.permissions import View
37#from Products.ZCatalog.ZCatalog import ZCatalog
38#from Products.CMFCore.permissions import ModifyPortalContent
39#from Products.CMFCore.permissions import ManagePortal
[3277]40from Products.CMFCore.utils import UniqueObject
[3172]41#from Products.CMFCore.URLTool import URLTool
42from Products.CMFCore.utils import getToolByName
43from Globals import package_home,INSTANCE_HOME
44from Products.AdvancedQuery import Eq, Between, Le,In
45import csv,re,os,sys
46from shutil import copy2
47import DateTime,time
48import logging
49p_home = package_home(globals())
50i_home = INSTANCE_HOME
51from utils import makeDigest
52
[3314]53NO_KEY = '----'
[3316]54IGNORE = 'ignore'
[3277]55class WAeUPImport(UniqueObject, SimpleItem, ActionProviderBase): ###(
[3172]56    """ WAeUPImport """
57    required_modes = ('create',)
58
[3277]59    def __init__(self,waeup_tool): ###(
60        self.students_folder = waeup_tool.portal_url.getPortalObject().campus.students
[3172]61        self.member = member = waeup_tool.portal_membership.getAuthenticatedMember()
[3320]62        self.import_date = DateTime.DateTime()
63        self.imported_by = str(member)
64        #self.current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
[3172]65        self.waeup_tool = waeup_tool
[4558]66        self.session = waeup_tool.getSessionId()[0]
[3248]67        self.academics_folder = waeup_tool.portal_url.getPortalObject().campus.academics
[3172]68        self.schema_tool = getToolByName(waeup_tool, 'portal_schemas')
69        self.layout_tool = getToolByName(waeup_tool, 'portal_layouts')
[3842]70        self.types_tool = getToolByName(waeup_tool, 'portal_types')
[3172]71        self.portal_workflow = getToolByName(waeup_tool, 'portal_workflow')
72        self.portal_url = getToolByName(waeup_tool, 'portal_url')
[3178]73        self.portal_catalog = waeup_tool.portal_catalog
[3822]74        self.portal_directories = waeup_tool.portal_directories
[3172]75        self.students_catalog = waeup_tool.students_catalog
76        self.courses_catalog = waeup_tool.courses_catalog
77        self.course_results = waeup_tool.course_results
[3984]78        self.payments_catalog = waeup_tool.payments_catalog
[3250]79        self.applicants_catalog = waeup_tool.applicants_catalog
[4302]80        self.removed_student_ids = waeup_tool.removed_student_ids
[3191]81        #self.mode = mode
82        # self.import_method = getattr(self, '%s' % mode,None)
[3172]83        errors = []
[3191]84        # if self.import_method is None:
85        #     errors.append('No importer method %s' % mode)
[3178]86        self.pending_path = "%s/import/%s.pending" % (i_home,self.plural_name)
87        self.pending_tmp = "%s/import/%s.pending.tmp" % (i_home,self.plural_name)
88        self.pending_backup = "%s/import/%s.pending.old" % (i_home,self.plural_name)
[3172]89        self.pending_fn = os.path.split(self.pending_path)[1]
[3178]90        self.imported_path = "%s/import/%s.imported" % (i_home,self.plural_name)
[3172]91        self.imported_fn = os.path.split(self.imported_path)[1]
92        iname = "import_%s" % self.name
[3249]93        self.logger = logging.getLogger('WAeUPImport.%sImport' % self.plural_name.capitalize())
[3172]94        self.schema = self.schema_tool._getOb(iname,None)
[3250]95        #self.pending_schema = self.schema_tool._getOb("%s_pending" % iname,None)
[3172]96        self.layout = self.layout_tool._getOb(iname,None)
[3250]97        while True:
98            if self.schema is None:
99                errors.append('no schema %s' % iname)
100            # if self.pending_schema is None:
101            #     self.pending_schema = self.schema
102            if self.layout is None:
103                errors.append('no such layout %s' % iname)
104            if errors:
105                break
106            self.data_keys = self.schema.keys()
107            self.csv_keys = self.schema.keys()
108            info = {}
109            info['imported_from'] = ''
[3326]110            info['import_record_no'] = 0
[3325]111            info['imported_by'] = self.imported_by
[3320]112            info['import_date'] = self.import_date.strftime("%d/%m/%y %H:%M:%S")
[3250]113            info['error'] = ''
114            self.info = info
115            self.csv_keys.extend(self.info)
116            self.validators = {}
117            for widget in self.layout.keys():
118                self.validators[widget] = self.layout[widget].validate
119            self.required_keys = {}
120            for mode in self.required_modes:
121                self.required_keys[mode] = [self.layout.getIdUnprefixed(id)
122                                    for id,widget in self.layout.objectItems()
123                                    if widget.is_required]
124            break
[3172]125        self.init_errors = ','.join(errors)
[3277]126    ###)
[3172]127
[3372]128    def findStudent(self,mode,student_id=None, matric_no=None, jamb_reg_no=None): ###(
[5515]129        #logger = logging.getLogger('WAeUPImport.findStudent')
[3372]130        student_record = None
131        msg = ''
132        key_used = ''
133        while True:
134            if student_id:
135                key_used = 'student_id'
136                res = self.students_catalog(id = student_id)
137                if not res:
138                    msg = "no student with id %s" % student_id
139                    break
140                student_record = res[0]
[5515]141                #if matric_no and student_record.matric_no:
142                #    if  matric_no != student_record.matric_no:
143                #        #msg = "old matric_no %s overwritten with %s" % (student_record.matric_no,matric_no)
144                #        logger.info("%s, old matric_no %s overwritten with %s" % (student_record.id,student_record.matric_no,matric_no))
145                #if jamb_reg_no and student_record.jamb_reg_no:
146                #    if jamb_reg_no != student_record.jamb_reg_no:
147                #        #msg = "old reg_no %s overwritten with %s" % (student_record.jamb_reg_no,jamb_reg_no)
148                #        logger.info("%s, old reg_no %s overwritten with %s" % (student_record.id,student_record.jamb_reg_no,jamb_reg_no))
[3372]149            elif jamb_reg_no:
150                key_used = 'jamb_reg_no'
151                res = self.students_catalog(jamb_reg_no = jamb_reg_no)
152                if res:
[3383]153                    if mode == 'create':
[3372]154                        msg = "jamb_reg_no exists"
155                        break
156                else:
157                    if mode == 'edit':
158                        msg = "no student with jamb_reg_no %s" % jamb_reg_no
159                        break
160                student_record = res[0]
161            elif matric_no:
162                key_used = 'matric_no'
163                res = self.students_catalog(matric_no = matric_no)
164                if not res:
165                    msg = "no student with matric_no %s" % matric_no
166                    break
167                student_record = res[0]
[3382]168            else:
[3383]169                msg = "neither id, matric_no nor reg_no specified"
[3372]170            break
171        d = {}
172        d['student_record'] = student_record
[3383]173        d['key_used'] = key_used
174        d['msg'] = msg
[3372]175        return d
176    ###)
177
[3277]178    def makeIdLists(self): ###(
[3172]179        pending_digests = []
180        pending = []
181        # pending_student_ids = []
182        # pending_matric_nos = []
183        # pending_reg_ns = []
184        if os.path.exists(self.pending_path):
185            datafile = open(self.pending_path,"r")
[3325]186            reader = csv.reader(datafile)
187            old_headline = reader.next()
188            #datafile.seek(0)
189            pending_csv_reader = csv.DictReader(datafile,old_headline,)
190            #pending_csv_reader.next() # skip headline
[3172]191            for item in pending_csv_reader:
192                digest = makeDigest(item,self.data_keys)
193                if digest not in pending_digests:
194                    pending_digests += digest,
195                    pending += item,
[3178]196            datafile.close()
[3268]197            #copy2(self.pending_path,self.pending_backup)
[3172]198        return pending, pending_digests
[3277]199    ###)
200
[3292]201    def checkHeadline(self,headline): ###(
[3315]202        """ check the headline of a csv file """
[3277]203        import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
204                                                        or k.strip() in self.info.keys())]
[3316]205        # import_keys = [k.strip() for k in headline if not (k.strip() in self.info.keys())]
[3277]206        diff2schema = set(import_keys).difference(set(self.schema.keys()))
207        diff2layout = set(import_keys).difference(set(self.layout.keys()))
208        #if diff2schema and diff2schema != set(['id',]):
209        if diff2schema:
210            return list(diff2schema)
211        return []
[3292]212    ###)
[3314]213
214    def getHeadlineFields(self,headline,values): ###(
[3315]215        """ check the headline of a csv file """
[3316]216        # import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
217        #                                                 or k.strip() in self.info.keys())]
218        import_keys = [k.strip() for k in headline if not (k.strip() in self.info.keys())]
[3347]219        info_keys = [k.strip() for k in headline if k.strip() in self.info.keys()]
[3314]220        si = set(import_keys)
221        ss = set(self.schema.keys())
[3315]222
[3314]223        invalid_keys = si - ss
224        keys = []
225        i = 0
[3316]226        duplicates = False
227        singels = []
228        msg = ''
229        while True:
230            if len(values) != len(import_keys):
[3347]231                if len(values) == len(import_keys) + len(info_keys):
[5613]232                    msg += "fields from pending data file in headline"
[3347]233                else:
234                    msg += "%d fields in headline but %d values" % (len(import_keys),len(values))
[3316]235                break
236            for k in import_keys:
237                if k in singels:
[3318]238                    keys += (k,'%s' % k,values[i],'(duplicate)'),
[3325]239                    msg += ("duplicate %s," % k)
[3318]240                    keys[singels.index(k)] = (k,'%s' % k,values[singels.index(k)],'(duplicate)')
[3316]241                elif k in invalid_keys and not k.startswith(IGNORE):
[3318]242                    keys += (k,NO_KEY,values[i],'(invalid)'),
[3316]243                else:
244                    keys += (k,k,values[i],''),
245                i += 1
246                singels += k,
247            break
248        return msg,keys
[3314]249    ###)
[3172]250###)
251
252class ApplicationImport(WAeUPImport):###(
[3250]253    name = "application"
[3172]254    plural_name = "%ss" % name
255    commit_after = 1000
256
257    def create(self,mapping):###(
258        reg_no = mapping.get('reg_no')
259        msg = ''
260        while True:
261            try:
262                self.applicants_catalog.addRecord(**mapping)
263            except ValueError:
264                msg =  "applicant record with reg_no %s already exists" % reg_no
265            break
266        return reg_no,msg,mapping
267    ###)
[4019]268   
269    def remove(self,mapping):
270        reg_no = mapping.get('reg_no')
271        msg = ''
272        while True:
273            if self.applicants_catalog.getRecordByKey(reg_no) is None:
274                msg =  "no application record with reg_no %(reg_no)s" % vars()
275                break
276            self.applicants_catalog.deleteRecord(reg_no)
277            break
278        return reg_no,msg,mapping   
279   
[3172]280    def edit(self,mapping):###(
281        reg_no = mapping.get('reg_no')
282        status = mapping.get('status')
[5456]283        jamb_reg_no = mapping.get('jamb_reg_no')
[3172]284        msg = ''
285        while True:
[5456]286            if jamb_reg_no:
287                res = self.applicants_catalog(jamb_reg_no = jamb_reg_no.upper())
288                if not len(res):
289                    res = self.applicants_catalog(jamb_reg_no = jamb_reg_no.lower())
290                if not len(res):
291                    msg =  "applicant record with jamb_reg_no %s does not exist" % jamb_reg_no
292                    break
293            else:
294                res = self.applicants_catalog(reg_no = reg_no)
[3172]295            if len(res):
296                if res[0].status == 'created' and status != 'created':
297                    msg =  "student object with id %s for %s already created, status cannot be changed" % (res[0].student_id, reg_no)
298                elif status == 'created' and res[0].status != 'created':
299                    msg =  "student object for %s has not yet been created, status cannot be set to 'created'" % (reg_no)
300                else:
301                    self.applicants_catalog.modifyRecord(**mapping)
302            else:
303                msg =  "applicant record with reg_no %s does not exist" % reg_no
304            break
305        return reg_no,msg,mapping
306    ###)
307
308###)
309
310class CertificateImport(WAeUPImport):###(
311    name = "certificate"
312    plural_name = "%ss" % name
313    commit_after = 100000
314
315    def create(self,mapping):###(
316        if getattr(self,'_v_certificate_list',None) is None:
317            self._v_certificate_list = []
318        if getattr(self,'_v_department_certificates',None) is None:
[3248]319            departments = self.portal_catalog(portal_type = "Department")
[3172]320            self._v_department_certificates = {}
[3355]321            for department  in departments:
322                certificates_container = getattr(department.getObject(),"certificates",None)
323                self._v_department_certificates[department.getId] = {'container': certificates_container,
324                                                            'certificates': certificates_container.objectIds(),
325                                                            }
[3248]326        department_id = mapping['department_code']
[3172]327        msg = ''
[3248]328        certificate_id = mapping.get('code')
[3172]329        while True:
[3248]330            department_certificates = self._v_department_certificates.get(department_id,None)
331            if department_certificates is None:
332                msg =  "No Department with ID: %s" % department_id
[3172]333                break
[3355]334            certificates_container = department_certificates['container']
335            certificates = department_certificates['certificates']
[3172]336            if certificate_id in self._v_certificate_list:
[3248]337                msg =  "Duplicate Certificate ID: %s" % department_id
[3172]338                break
[3355]339            if certificate_id in certificates:
[3248]340                msg =  "Duplicate Certificate ID: %s" % department_id
[3172]341                break
342            try:
[3355]343                certificates_container.invokeFactory('Certificate', certificate_id)
[3172]344            except BadRequest,E:
345                msg =  "%s" % E
346                break
347            self._v_certificate_list.append(certificate_id)
[3355]348            certificate = getattr(certificates_container,certificate_id)
349            certificate.getContent().edit(mapping=mapping)
[3172]350            break
351        return certificate_id,msg,mapping
352    ###)
353
354    def edit(self,mapping):###(
355        certificate_id = mapping.get('code')
356        res = self.portal_catalog(id=certificate_id)
357        msg = ''
358        while True:
359            if not res:
[3233]360                msg =  "no certificate with id: %s" % certificate_id
[3172]361                break
362            c = res[0].getObject()
363            c.getContent().edit(mapping=mapping)
364            break
365        return certificate_id,msg,mapping
366    ###)
367###)
368
369class CourseImport(WAeUPImport):###(
370    name = "course"
371    plural_name = "%ss" % name
372    commit_after = 1000
373
374    def create(self,mapping):###(
375        if getattr(self,'_v_course_list',None) is None:
376            self._v_course_list = []
[3179]377        if getattr(self,'_v_department_courses',None) is None:
378            departments = self.portal_catalog(portal_type = "Department")
[3172]379            self._v_department_courses = {}
[3179]380            for department in departments:
[3355]381                courses_container = getattr(department.getObject(),"courses",None)
382                if courses_container is not None:
383                    self._v_department_courses[department.getId] = {'container': courses_container,
384                                                                    'courses': courses_container.objectIds(),
385                                                                   }
[3179]386        department_id = mapping['department_code']
387        course_id = mapping.get('code','')
[3172]388        msg = ''
389        while True:
[3179]390            department_courses = self._v_department_courses.get(department_id,None)
391            if department_courses is None:
[3233]392                msg =  "no department with id: %(department_id)s" % vars()
[3172]393                break
[3355]394            courses_container = department_courses['container']
395            courses = department_courses['courses']
[3172]396            if course_id in self._v_course_list:
[3233]397                msg =  "duplicate course id: %(course_id)s" % vars()
[3172]398                break
[3355]399            if course_id in courses:
[3233]400                msg =  "course %(course_id)s already exists in department %(department_id)s" % vars()
[3172]401                break
402            try:
[3355]403                courses_container.invokeFactory('Course', course_id)
[3172]404            except BadRequest,E:
405                msg =  "%s" % E
406                break
407            self._v_course_list.append(course_id)
[3355]408            course = getattr(courses_container,course_id)
[3179]409            course.getContent().edit(mapping=mapping)
[3172]410            break
411        return course_id,msg,mapping
412    ###)
413
414    def edit(self,mapping): ###(
[3179]415        course_id = mapping.get('code','')
[3248]416        course = self.courses_catalog.getRecordByKey(course_id)
[3355]417        msg = ''
[3172]418        while True:
[3248]419            if course is None:
[3233]420                msg =  "no course with id: %s" % course_id
[3172]421                break
[3355]422            course_object = getattr(getattr(getattr(getattr(self.academics_folder,course.faculty),
423                                    course.department),
424                                    'courses'),
425                                    course_id)
[3248]426            course_object.getContent().edit(mapping=mapping)
[3172]427            break
428        return course_id,msg,mapping
429    ###)
[3823]430
431    def remove(self,mapping): ###(
432        course_id = mapping.get('code','')
433        course = self.courses_catalog.getRecordByKey(course_id)
434        msg = ''
435        while True:
436            if course is None:
437                msg =  "no course with id: %s" % course_id
438                break
439            courses = getattr(getattr(getattr(self.academics_folder,course.faculty),
440                                    course.department),
441                                    'courses')
442            courses.manage_delObjects((course_id),)     
443            break
444        return course_id,msg,mapping
445    ###)   
446   
[3172]447###)
448
449class CourseResultImport(WAeUPImport):###(
450    """ CourseresultImport """
451    name = "course_result"
452    plural_name = "%ss" % name
453    commit_after = 1000000
[3233]454    required_modes = ('create','edit','remove')
[3172]455
456    def create(self,mapping):###(
457        students_folder = self.portal_url.getPortalObject().campus.students
458        if getattr(self,'_v_courses',None) is None:
459            res = self.courses_catalog()
460            self._v_courses = {}
461            for brain in res:
462                self._v_courses[brain.code] = brain
463        if getattr(self,'_v_level_created',None) is None:
464            self._v_level_created = []
[3372]465        if getattr(self,'_v_student_study_course',None) is None:
466            self._v_student_study_course = {}
[3172]467        msg = ''
468        key = ''
[3372]469        matric_no = mapping.get('matric_no','')
470        id = mapping.get('id','')
[3172]471        while True:
472            course_id = mapping.get('code')
473            if course_id not in self._v_courses.keys():
[3233]474                msg = "no course with id: %s" % course_id
[3172]475                break
[3372]476            result = self.findStudent('create',student_id=id,matric_no=matric_no)
477            msg = result['msg']
478            if msg:
479                break
480            student_record = result['student_record']
481            student_id = mapping['student_id']  = student_record.id
482            level_id = mapping.get('level_id','')
483            code = mapping.get('code','')
484            level_ident = "%(student_id)s_%(level_id)s" % vars()
485            if level_ident not in self._v_level_created:
486                context = self._v_student_study_course.get(student_id,None)
487                if context is None:
488                    try:
489                        context = getattr(getattr(students_folder,
490                                                "%(student_id)s" % vars()),
491                                        'study_course')
492                        self._v_student_study_course[student_id] = context
493                    except:
494                        msg = "could not create level %(level_id)s for %(student_id)s" % vars()
495                        break
496                if level_id not in context.objectIds():
497                    context.invokeFactory('StudentStudyLevel',"%(level_id)s" % vars())
498                    level = getattr(context,"%(level_id)s" % vars())
499                    self.portal_workflow.doActionFor(level,'open')
[3485]500                    session_id = mapping.get('session_id','')
501                    if session_id:
502                        level.getContent().edit(mapping={'session': "%s" % session_id,})
[3372]503                    self.portal_workflow.doActionFor(level,'close')
504                    self._v_level_created += level_ident,
505            mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
[3431]506            #overwrite semester and credits in create mode
[3372]507            for k in ('semester','credits',):
508                mapping[k] = getattr(self._v_courses[course_id],k)
[5063]509            # edit course result in create mode if it exists
510            if self.course_results.getRecordByKey(key) is None:
511                try:
512                    self.course_results.addRecord(**mapping)
513                except ValueError:
514                    msg = "unknown error: %s" % key
515            else:
516                self.course_results.modifyRecord(**mapping)
[3372]517            break
518        return key,msg,mapping
519    ###)
520
[3374]521    def edit(self,mapping): ###(
[3372]522        msg = ''
523        key = ''
524        matric_no = mapping.get('matric_no','')
[3374]525        id = mapping.get('id','')
[3372]526        while True:
527            result = self.findStudent('edit',student_id=id,matric_no=matric_no)
528            msg = result['msg']
[3172]529            if msg:
530                break
[3372]531            student_record = result['student_record']
[3336]532            student_id = student_record.id
[3248]533            level_id = mapping.get('level_id','')
534            code = mapping.get('code','')
[3431]535            #code = mapping['code']
[3172]536            mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
[3330]537            if self.course_results.getRecordByKey(key) is None:
538                msg =  "no course result with key %(key)s" % vars()
539                break
[5204]540            # don't overwrite session id but check if session ids match
541            # (helps to avoid overwriting of course results)
542            session_in_course_result = self.course_results.getRecordByKey(key)['session_id']
[5206]543            if mapping.get('session_id','') and not session_in_course_result == mapping.get('session_id',''):
[5204]544                msg =  "import session_id %s does not match session_id %s in course result" % (mapping['session_id'],session_in_course_result)
[5212]545                break
[3330]546            self.course_results.modifyRecord(**mapping)
[3172]547            break
548        return key,msg,mapping
549    ###)
550
[3195]551    def remove(self,mapping):###(
[3233]552        key = ''
[3172]553        msg = ''
[3374]554        matric_no = mapping.get('matric_no','')
555        id = mapping.get('id','')
[3172]556        while True:
[3374]557            result = self.findStudent('edit',student_id=id,matric_no=matric_no)
558            msg = result['msg']
[3172]559            if msg:
560                break
[3374]561            student_record = result['student_record']
[3172]562            student_id = student_record.id
[3248]563            level_id = mapping.get('level_id','')
564            code = mapping.get('code','')
[3172]565            key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
566            if self.course_results.getRecordByKey(key) is None:
[3233]567                msg =  "no course result with key %(key)s" % vars()
[3172]568                break
569            self.course_results.deleteRecord(key)
570            break
571        return key,msg,mapping
572    ###)
573###)
574
575class CertificateCourseImport(WAeUPImport):###(
576    name = "certificate_course"
577    plural_name = "%ss" % name
[3741]578    commit_after = 1000
[3219]579    required_modes = ('create','edit')
[3172]580
581    def create(self,mapping):
582        if getattr(self,'_v_courses',None) is None:
583            res = self.courses_catalog()
584            self._v_courses= [course.code for course in res]
585        if getattr(self,'_v_ceritficates',None) is None:
586            res = self.portal_catalog(portal_type = "Certificate")
587            self._v_certificates = {}
588            for cert in res:
589                self._v_certificates[cert.getId] = cert.getObject()
590        msg = ''
591        while True:
592            certificate_course_id = mapping.get('code')
593            if certificate_course_id not in self._v_courses:
[3233]594                msg =  "no course with id: %s" % certificate_course_id
[3172]595                break
596            cert_id = mapping['certificate_code']
597            cert = self._v_certificates.get(cert_id,None)
598            if cert is None:
[3233]599                msg =  "no certificate with id: %s" % cert_id
[3172]600                break
601            level_id = mapping.get('level')
602            level = getattr(cert,level_id,None)
603            if level is None:
604                cert.invokeFactory('StudyLevel', level_id)
605                level = getattr(cert,level_id,None)
606            elif hasattr(level,certificate_course_id):
[3233]607                msg =  "duplicate certificate course id: %(certificate_course_id)s " % vars()
[3172]608                msg += "in %(cert_id)s/ %(level_id)s" % vars()
609                break
610            level.invokeFactory('CertificateCourse', certificate_course_id)
611            c = getattr(level,certificate_course_id)
612            c.getContent().edit(mapping=mapping)
613            break
614        return certificate_course_id,msg,mapping
615    ###)
616
617class DepartmentImport(WAeUPImport):###(
618    name = "department"
619    plural_name = "%ss" % name
[3178]620    commit_after = 1000
[3207]621
[3172]622    def create(self,mapping):###(
623        "create a department in the correct faculty"
[3178]624        faculty_id = mapping['faculty_code']
[3172]625        msg = ''
626        if getattr(self,'_v_faculties',None) is None:
[3549]627            res = self.portal_catalog(portal_type = "Faculty")
[3172]628            self._v_faculties = {}
629            for f in res:
630                self._v_faculties[f.getId] = f.getObject()
[3178]631        department_id = mapping.get('code','')
[3172]632        while True:
[3178]633            faculty = self._v_faculties.get(faculty_id,None)
634            if faculty is None:
[3233]635                msg =  "no faculty with id: %s" % faculty_id
[3172]636                break
637            else:
[3178]638                d = getattr(faculty,department_id,None)
[3172]639                if d is None or d.portal_type == "Faculty":
640                    try:
[3178]641                        faculty.invokeFactory('Department', department_id)
[3172]642                    except BadRequest,E:
643                        msg =  "%s" % E
644                        break
[3178]645                    d = getattr(faculty,department_id)
[3172]646                    d.invokeFactory('CoursesFolder','courses')
647                    courses = getattr(d,'courses')
648                    dict = {'Title': 'Courses'}
649                    courses.getContent().edit(mapping=dict)
650                    d.invokeFactory('CertificatesFolder','certificates')
651                    certificates = getattr(d,'certificates')
652                    dict = {'Title': 'Certificates'}
653                    certificates.getContent().edit(mapping=dict)
654                    d.getContent().edit(mapping=mapping)
655            break
[3178]656        return department_id,msg,mapping
[3172]657    ###)
658
659    def edit(self,mapping): ###(
[3178]660        "edit a department in the correct faculty"
[3172]661        academics_folder = self.portal_url.getPortalObject().campus.academics
[3178]662        faculty_id = mapping['faculty_code']
663        department_id = mapping.get('code','')
[3172]664        msg = ''
665        while True:
666            try:
[3178]667                d = getattr(getattr(academics_folder,faculty_id),department_id,None)
[3172]668            except KeyError:
[3233]669                msg =  "department %s or faculty %s wrong" % (department_id,faculty_id)
[3172]670                break
[3178]671            if d is None or d.portal_type == "Faculty":
[3233]672                msg =  "department %s not found" % (department_id)
[3178]673                break
674            d.getContent().edit(mapping=mapping)
[3172]675            break
[3178]676        return department_id,msg,mapping
[3172]677    ###)
678###)
679
680class FacultyImport(WAeUPImport):###(
681    name = "faculty"
[3177]682    plural_name = "faculties"
[3172]683    commit_after = 100
[3548]684   
[3172]685
686    def create(self,mapping): ###(
687        "create a faculty"
688        academics_folder = self.portal_url.getPortalObject().campus.academics
[3178]689        faculty_id = mapping.get('code','')
[3172]690        msg = ''
691        while True:
[3178]692            if faculty_id in academics_folder.objectIds():
[3233]693                msg =  "faculty with id: %s exists" % faculty_id
[3172]694                break
695            try:
[3178]696                academics_folder.invokeFactory('Faculty', faculty_id)
[3172]697            except BadRequest,E:
698                msg =  "%s" % E
699                break
[3178]700            f = getattr(academics_folder,faculty_id,None)
[3172]701            f.getContent().edit(mapping=mapping)
[3177]702            break
[3178]703        return faculty_id,msg,mapping
[3172]704        ###)
705
706    def edit(self,mapping): ###(
707        "edit a faculty"
708        academics_folder = self.portal_url.getPortalObject().campus.academics
[3178]709        faculty_id = mapping['code']
[3172]710        msg = ''
711        while True:
[3178]712            f = getattr(academics_folder,faculty_id,None)
[3172]713            if f is None:
[3233]714                msg =  "faculty with id: %s does not exist" % faculty_id
[3172]715            f.getContent().edit(mapping=mapping)
[3177]716            break
[3178]717        return faculty_id,msg,mapping
[3172]718    ###)
719###)
720
721class StudentImport(WAeUPImport):###(
722    name = "student"
723    plural_name = "%ss" % name
[8058]724    commit_after = 500
[3207]725
[3172]726    field2types_student = {   ###(
727                      'StudentApplication':
728                          {'id': 'application',
[3481]729                           #'title': 'Application Data',
[3172]730                           'wf_transition_return': 'close',
731                           'wf_transition_admit': 'remain',
[3726]732                           'wf_transition_graduate': 'close',
[3738]733                           'wf_transition_pay_school_fee': 'close',
[3820]734                           'wf_transition_validate_courses': 'close',
[5192]735                           'wf_transition_reject_clearance': 'remain',
[3172]736                           'fields':
737                             ('jamb_reg_no',
738                              'entry_mode',
739                              'entry_session',
740                              'jamb_score',
741                              'app_email',
[3987]742                              'app_mobile',
[3172]743                              'jamb_age',
744                              'jamb_state',
745                              'jamb_lga',
746                              'jamb_sex',
[3987]747                              'app_ac_pin',
748                              'app_reg_pin',
749                              'app_ac_date',                             
[3172]750                              )
751                              },
752                      'StudentClearance':
753                          {'id': 'clearance',
[3481]754                           #'title': 'Clearance/Eligibility Record',
[3172]755                           'wf_transition_return': 'close',
756                           'wf_transition_admit': 'remain',
[3726]757                           'wf_transition_graduate': 'close',
[3738]758                           'wf_transition_pay_school_fee': 'close',
[3820]759                           'wf_transition_validate_courses': 'close',
[5192]760                           'wf_transition_reject_clearance': 'open',
[3172]761                           'fields':
[3987]762                              ('matric_no',
[3172]763                              'nationality',
764                              'lga',
765                              'birthday',
[3987]766                              'clr_ac_pin',
767                              'request_date',
768                              'cleared_date',
769                              'clearance_officer',
[3172]770                              )
771                              },
772                         'StudentPersonal':
773                          {'id': 'personal',
[3481]774                           #'title': 'Personal Data',
[3172]775                           'wf_transition_return': 'open',
776                           'wf_transition_admit': 'remain',
[3726]777                           'wf_transition_graduate': 'close',
[3738]778                           'wf_transition_pay_school_fee': 'open',
[3820]779                           'wf_transition_validate_courses': 'open',
[5192]780                           'wf_transition_reject_clearance': 'remain',
[3172]781                           'fields':
782                             ('firstname',
783                              'middlename',
784                              'lastname',
785                              'sex',
786                              'email',
787                              'phone',
788                              'perm_address',
[3987]789                              'marit_stat',
790                              'disabled',
[3172]791                              )
792                              },
793                         'StudentStudyCourse':
794                          {'id': 'study_course',
[3481]795                           #'title': 'Study Course',
[3172]796                           'wf_transition_return': 'open',
797                           'wf_transition_admit': 'remain',
[3726]798                           'wf_transition_graduate': 'close',
[3738]799                           'wf_transition_pay_school_fee': 'open',
[3820]800                           'wf_transition_validate_courses': 'open',
[5192]801                           'wf_transition_reject_clearance': 'remain',
[3172]802                           'fields':
803                             ('study_course',
804                              'current_level',
805                              'current_session',
[3780]806                              'current_mode',  #is no longer used and visible but can still be imported
[3172]807                              'current_verdict',
808                              'previous_verdict',
809                              )
810                              },
[4558]811                         'StudentAccommodation':
812                          {'id': 'accommodation_final',
813                           'title': '',
814                           'wf_transition_return': 'remain',
815                           'wf_transition_admit': 'remain',
816                           'wf_transition_graduate': 'remain',
817                           'wf_transition_pay_school_fee': 'remain',
818                           'wf_transition_validate_courses': 'remain',
[5192]819                           'wf_transition_reject_clearance': 'remain',
[4558]820                           'fields':
821                           ('acco_maint_date',
822                              'acco_maint_code',
823                              'acco_maint_fee',
824                              'acco_maint_sc_pin',
825                              'acco_maint_pay_id',
826                              'acco_res_date',
827                              'acco_res_sc_pin',
828                              'bed',
829                              'session',
830                              'student_status',
831                              )     
832                              },
[3172]833                         'PaymentsFolder':
834                          {'id': 'payments',
[3481]835                           #'title': 'Payments',
[3172]836                           'wf_transition_return': 'open',
837                           'wf_transition_admit': 'open',
[3726]838                           'wf_transition_graduate': 'close',
[3738]839                           'wf_transition_pay_school_fee': 'open',
[3820]840                           'wf_transition_validate_courses': 'open',
[5192]841                           'wf_transition_reject_clearance': 'remain',
[3172]842                           'fields':
843                             ()
844                              },
845                         }
846    ###)
847
848    def create(self,mapping): ###(
849        "create student records due import"
[3726]850        logger = logging.getLogger('WAeUPImport.StudentImport.create')
[3172]851        students_folder = self.portal_url.getPortalObject().campus.students
852        jamb_reg_no = mapping.get('jamb_reg_no',None)
[3185]853        matric_no = mapping.get('matric_no',None)
[3705]854        entry_mode = mapping.get('entry_mode',None)
[3987]855        password = mapping.get('password',None)
[3172]856        msg = ''
[3185]857        student_id = mapping.get('id',None)
[3172]858        while True:
[3185]859            if student_id:
[3987]860                #msg = "student_id must not be specified in create mode"
861                #break
862                res = self.students_catalog(id = student_id)
863                if res:
864                    msg = "student_id %s already assigned" % res[0].id
[4531]865                    break     
866                self.waeup_tool.restorePictureFolder(student_id)           
[3987]867            else:
868                student_id = self.waeup_tool.generateStudentId('?')
[3705]869            if jamb_reg_no and not entry_mode == 'transfer':
[3172]870                res = self.students_catalog(jamb_reg_no = jamb_reg_no)
871                if res:
[3404]872                    msg = "jamb_reg_no already assigned to student %s" % res[0].id
[3172]873                    break
874            if matric_no:
875                res = self.students_catalog(matric_no = matric_no)
876                if res:
[3404]877                    msg = "matric_no already assigned to student %s" % res[0].id
[3172]878                    break
[3208]879            if not matric_no and not jamb_reg_no:
[3185]880                msg = "jamb_reg_no or matric_no must be specified"
881                break
[3987]882           
[3172]883            students_folder.invokeFactory('Student', student_id)
884            student_obj = getattr(students_folder,student_id)
885            f2t = self.field2types_student
886            d = {}
887            transition = mapping.get('reg_transition','admit')
[5504]888            if transition == 'admitted':
889                transition = 'admit'
890            elif transition == 'returning':
891                transition = 'return'
[5192]892            if transition not in ('admit','return','pay_school_fee','validate_courses','graduate','reject_clearance'):
[3172]893                msg = "no valid transition provided"
894                break
895            for pt in f2t.keys():
[4558]896                if pt == 'StudentAccommodation':
897                    if mapping.get('bed',None):
898                        student_obj.invokeFactory(pt,f2t[pt]['id'])
899                    else:
900                        continue
901                else:
902                    student_obj.invokeFactory(pt,f2t[pt]['id'])
[3172]903                sub_obj = getattr(student_obj,f2t[pt]['id'])
904                sub_doc = sub_obj.getContent()
[3481]905                #d['Title'] = f2t[pt]['title']
[3172]906                for field in f2t[pt]['fields']:
907                    d[field] = mapping.get(field,'')
[3207]908
[3172]909                if pt == "StudentApplication":
910                    #d['jamb_sex']  = 'M'
911                    #if mapping.get('sex'):
912                    #    d['jamb_sex']  = 'F'
913                    d['jamb_firstname'] = mapping.get('firstname',None)
914                    d['jamb_middlename'] = mapping.get('middlename',None)
915                    d['jamb_lastname'] = mapping.get('lastname',None)
[3207]916
[3172]917                # if pt == "StudyCourse":
918                #     for von,zu in (('entry_mode','current_mode'),
919                #                    ('entry_session','current_session')):
920                #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
921                #             d[zu] = mapping[von]
922                sub_doc.edit(mapping = d)
[3207]923
[3172]924                #import pdb;pdb.set_trace()
925                new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
926                if new_state != "remain":
927                    self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
928            self.portal_workflow.doActionFor(student_obj,transition)
929            student_obj.manage_setLocalRoles(student_id, ['Owner',])
[3179]930            mapping['id'] = student_id
[3987]931            if password:
932                self.waeup_tool.makeStudentMember(student_id,password)
[3172]933            break
934        return student_id,msg,mapping
935    ###)
936
[3822]937    def remove(self,mapping): ###(
938        "remove student records due import"
939        logger = logging.getLogger('WAeUPImport.StudentImport.remove')
940        students_folder = self.portal_url.getPortalObject().campus.students
941        stdir = self.portal_directories.students
942        student_id = mapping.get('id',None)
943        msg = ''
944        export_file = "%s/export/students_removed.csv" % (i_home)
[3984]945        reimport_file = "%s/export/students_for_reimport.csv" % (i_home)
[3822]946       
[3984]947        toexport_for_reimport = {
[3987]948       
[3984]949                    'application':
950                             ('jamb_reg_no',
951                              'entry_mode',
952                              'entry_session',
953                              'jamb_score',
954                              'app_email',
[3987]955                              'app_mobile',
[3984]956                              'jamb_age',
957                              'jamb_state',
958                              'jamb_lga',
959                              'jamb_sex',
[3987]960                              'app_ac_pin',
961                              'app_reg_pin',
962                              'app_ac_date',                             
[3984]963                              ),
[3987]964                    'clearance':
965                              ('matric_no',
966                              'nationality',
967                              'lga',
968                              'birthday',
969                              'clr_ac_pin',
970                              'request_date',
971                              'cleared_date',
972                              'clearance_officer',
973                              ),
[3984]974                    'study_course':
975                              ('study_course',
976                              'current_level',
977                              'current_session',
978                              'current_verdict',
979                              'previous_verdict',
[3987]980                              ),
981                    'personal': 
982                             ('firstname',
983                              'middlename',
984                              'lastname',
985                              'sex',
986                              'email',
987                              'phone',
988                              'perm_address',
989                              'marit_stat',
990                              'disabled',
991                              ),
[4558]992                    'accommodation': 
993                             ('acco_maint_date',
994                              'acco_maint_code',
995                              'acco_maint_fee',
996                              'acco_maint_sc_pin',
997                              'acco_maint_pay_id',
998                              'acco_res_date',
999                              'acco_res_sc_pin',
1000                              'bed',
1001                              'session',
1002                              'student_status',
1003                              ),                             
[3984]1004                   }
[3842]1005
[4558]1006        sub_types = ['StudentApplication','StudentClearance','StudentPersonal','StudentStudyCourse','StudentAccommodation']
[3842]1007        non_image_keys = {}
1008        for i in sub_types:
1009            pt_ob = getattr(self.types_tool,i)
1010            sub_schemas = pt_ob.schemas
1011            for i in sub_schemas:
1012                if i.startswith('student_'):
1013                    schema = getattr(self.schema_tool,i)
1014                    field_id = i.replace('student_','')
1015                    non_image_keys[field_id] = [key for key in schema.keys()
[3990]1016                                                if schema[key].meta_type != "CPS Image Field"]
1017       
1018        # export field names must be unique but, unfortunately, firstname, middlename and lastname are not
1019        # thus we have to omit them
1020        non_image_keys['clearance'].remove('firstname')
1021        non_image_keys['clearance'].remove('middlename')
1022        non_image_keys['clearance'].remove('lastname')
[3842]1023        toexport = non_image_keys
[4558]1024        #import pdb;pdb.set_trace()
[3822]1025        while True:
1026            if hasattr(students_folder,student_id):
1027                # begin export
1028                line = []
[3984]1029                fields = ['student_id','reg_state','password']
1030                line_for_reimport = []
1031                fields_for_reimport = ['student_id','reg_state','password','import_mode']               
1032                #fields = []
1033                #for f in self.students_catalog.schema():
1034                #    fields.append(f)               
[3822]1035                for k in toexport.keys():
1036                    for f in toexport[k]:
1037                        fields.append(f)
[3984]1038                for k in toexport_for_reimport.keys():
1039                    for f in toexport_for_reimport[k]:
1040                        fields_for_reimport.append(f)                       
[3990]1041                if not os.path.exists(export_file):       
[3822]1042                    headline = ','.join(fields)
1043                    open(export_file,"a").write(headline +'\n')
[3990]1044                if not os.path.exists(reimport_file): 
[3984]1045                    headline_for_reimport = ','.join(fields_for_reimport)                   
1046                    open(reimport_file,"a").write(headline_for_reimport +'\n')                   
[3822]1047                format = '"%(' + ')s","%('.join(fields) + ')s"'
[3984]1048                format_for_reimport = '"%(' + ')s","%('.join(fields_for_reimport) + ')s"'
[3822]1049                res = self.students_catalog(id = student_id)
1050                student = res[0]
1051                student_obj = getattr(students_folder,student_id)
[3984]1052                #d = student.getFormattedStudentEntry(student)
1053                d = {'student_id':student_id,'reg_state':student.review_state,'import_mode':'create'}
[3822]1054                for k in toexport.keys()[0:]:
[4558]1055                    if k.startswith('acco'):
1056                        session = self.session
1057                        subobject = 'accommodation_' + session
1058                    else:
1059                        subobject = k
[3822]1060                    try:
[4558]1061                        object = getattr(student_obj,subobject)
[3822]1062                        object_doc = object.getContent()
1063                    except:
[4558]1064                        for f in toexport[k]:
1065                            d[f] = ''
[3822]1066                        continue
1067                    for f in toexport[k]:
1068                        d[f] = getattr(object_doc,f,'')
[3863]1069                if hasattr(stdir, student_id):
1070                    d['password'] = self.waeup_tool.getCredential(student_id)
1071                    stdir.deleteEntry(student_id)
[4023]1072                else:
1073                    d['password'] = "not set"
[3863]1074                self.waeup_tool.removePictureFolder(student_id)       
[3822]1075                line.append(format % d)
1076                open(export_file,"a").write('\n'.join(line) +'\n')
[3984]1077                line_for_reimport.append(format_for_reimport % d)
1078                open(reimport_file,"a").write('\n'.join(line_for_reimport) +'\n')               
[3988]1079                self.course_results.exportRemoveAllCourses(student_id = student_id, export = True, remove = True)
[5020]1080                # remove should be false, otherwise an uncatalog error occurs if payment objects exist
1081                self.payments_catalog.exportRemoveAllPayments(student_id = student_id, export = True, remove = False)
[3984]1082                self.waeup_tool.exportAllStudyLevels(student_id = student_id)
[3822]1083                # end export
[4302]1084                students_folder.manage_delObjects((student_id),) 
1085                try:
1086                    self.removed_student_ids.addRecord(id = student_id)
1087                except: 
1088                    msg = "Student already in removed_student_ids"
[3822]1089            else:
1090                msg = "Student object not found"
1091                break
[3863]1092     
[3822]1093            break
1094        return student_id,msg,mapping     
1095
1096
[3179]1097    def edit(self,mapping): ###(
[3402]1098        "edit student records due import"
[3172]1099        wftool = self.portal_workflow
[3726]1100        logger = logging.getLogger('WAeUPImport.StudentImport.edit')
[3172]1101        students_folder = self.portal_url.getPortalObject().campus.students
1102        student_id = mapping.get('id',None)
1103        jamb_reg_no = mapping.get('jamb_reg_no',None)
1104        matric_no = mapping.get('matric_no',None)
1105        editable_keys = mapping.keys()
[3999]1106        password = mapping.get('password',None)
[3172]1107        msg = ''
1108        while True:
1109            if student_id:
1110                res = self.students_catalog(id = student_id)
1111                if not res:
1112                    msg = "no student with id %s" % student_id
1113                    break
1114                student_record = res[0]
1115                if matric_no and student_record.matric_no:
[3705]1116                    if  matric_no != student_record.matric_no and not matric_no == 'transferred':
[3402]1117                        res = self.students_catalog(matric_no = matric_no)
1118                        if res:
[3404]1119                            msg = "matric_no already assigned to student %s" % res[0].id
[3402]1120                            break
[3172]1121                        msg = "old matric_no %s overwritten with %s" % (student_record.matric_no,matric_no)
1122                        #logger.info("%s, old matric_no %s overwritten with %s" % (student_record.id,student_record.matric_no,matric_no))
1123                if jamb_reg_no and student_record.jamb_reg_no:
1124                    if jamb_reg_no != student_record.jamb_reg_no:
[3404]1125                        res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1126                        if res:
1127                            msg = "jamb_reg_no already assigned to student %s" % res[0].id
[3431]1128                            break
[3404]1129                        msg = "old jamb_reg_no %s overwritten with %s" % (student_record.jamb_reg_no,jamb_reg_no)
[3172]1130                        #logger.info("%s, old reg_no %s overwritten with %s" % (student_record.id,student_record.jamb_reg_no,jamb_reg_no))
1131            elif jamb_reg_no:
1132                res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1133                if not res:
1134                    msg = "no student with jamb_reg_no %s" % jamb_reg_no
1135                    break
1136                student_record = res[0]
1137                editable_keys.remove('jamb_reg_no')
1138            elif matric_no:
1139                res = self.students_catalog(matric_no = matric_no)
1140                if not res:
1141                    msg = "no student with matric_no %s" % matric_no
1142                    break
1143                student_record = res[0]
1144                editable_keys.remove('matric_no')
1145            student_id = student_record.id
1146            student_obj = getattr(students_folder,student_id)
1147            f2t = self.field2types_student
1148            d = {}
1149            any_change = False
1150            #special treatment for StudentStudyLevel
1151            d['verdict']  = mapping.get('current_verdict','')
1152            d['session']  = mapping.get('current_session','')
1153            current_level = mapping.get('current_level','')
[3726]1154            transition = mapping.get('reg_transition',None)
[5183]1155            change_reg_state = mapping.get('change_reg_state',None)  # for brute force method
[3820]1156            # the validate_courses import transition is not really useful because it does not execute validate_courses.py
[5196]1157            if transition and transition not in ('admit','return','graduate','pay_school_fee','validate_courses','reject_clearance'):
[3726]1158                msg = "no valid transition provided"
1159                break     
[5232]1160            if transition:
1161                #import pdb;pdb.set_trace()
1162                try:
1163                    self.portal_workflow.doActionFor(student_obj,transition)
1164                except:
1165                    msg = "reg_transition not allowed"
1166                    break
1167            elif change_reg_state:
1168                msg = self.waeup_tool.changeStudentState(student_obj, change_reg_state)   
1169                if msg:
1170                    break             
1171               
[3172]1172            while d['session'] and d['verdict'] and current_level:
1173                sub_obj = getattr(student_obj,'study_course',None)
1174                if sub_obj is None:
1175                    break
1176                level_obj = getattr(sub_obj,current_level,None)
1177                if  level_obj is None:
1178                    break
1179                any_change = True
1180                level_obj.getContent().edit(mapping = d)
1181                try:
1182                    wftool.doActionFor(level_obj,'close')
1183                except:
1184                    pass
1185                break
[3726]1186           
[3172]1187            for pt in f2t.keys():
1188                #if pt == "StudentApplication":
1189                #    d['jamb_sex']  = 'M'
1190                #    if mapping.get('sex'):
1191                #        d['jamb_sex']  = 'F'
1192                intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
[3726]1193                #import pdb;pdb.set_trace()
1194                object_id = f2t[pt]['id']
1195                sub_obj = getattr(student_obj,object_id,None)
[3172]1196                if intersect and pt not in ('StudentStudyLevel',):
1197                    if sub_obj is None:
1198                        try:
1199                            student_obj.invokeFactory(pt,object_id)
1200                        except:
1201                            continue
1202                        sub_obj = getattr(student_obj,object_id)
[3481]1203                        #if f2t[pt]['title'] != '':
1204                        #    d['Title'] = f2t[pt]['title']
[3172]1205                    sub_doc = sub_obj.getContent()
1206                    for field in intersect:
1207                        changed = False
1208                        if getattr(sub_doc,field,None) != mapping.get(field,''):
1209                            any_change = True
1210                            changed = True
1211                            d[field] = mapping.get(field,'')
1212                        if changed:
1213                            sub_doc.edit(mapping = d)
[3726]1214                if transition:
1215                    new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1216                    if new_state != "remain":
1217                        try:
1218                            self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1219                        except:
1220                            pass
[5183]1221             
[3999]1222            if password:
1223                self.waeup_tool.editPassword(student_id,password)
[3172]1224            break
1225        return student_id,msg,mapping
1226    ###)
[3179]1227###)
[3172]1228
[3372]1229class StudentStudyLevelImport(WAeUPImport):###(
1230    """ StudentStudyLevelImport """
1231    name = "student_study_level"
1232    plural_name = "%ss" % name
[5184]1233    commit_after = 1000
[3372]1234    required_modes = ('create',)
1235
[3381]1236    def create(self,mapping): ###(
[3372]1237        "edit student levels and create StudentStudyLevel object if not existent"
1238        wftool = self.portal_workflow
[3988]1239        logger = logging.getLogger('WAeUPImport.StudentStudyLevelImport.create')
[3372]1240        students_folder = self.portal_url.getPortalObject().campus.students
1241        student_id = mapping.get('id',None)
1242        matric_no = mapping.get('matric_no',None)
1243        editable_keys = mapping.keys()
1244        key = ''
1245        msg = ''
1246        while True:
1247            result = self.findStudent('create',student_id=student_id,matric_no=matric_no)
1248            msg = result['msg']
1249            if msg:
1250                break
1251            student_record = result['student_record']
1252            student_id = student_record.id
1253            mapping['id'] = student_id
1254            session = mapping.get('session','')
1255            level = key = mapping.get('code','')
1256            if not level.isdigit():
1257                msg = 'student %s: imported level is empty' % (student_id,)
1258                break
[3381]1259            study_course_obj = getattr(getattr(students_folder,student_id),'study_course',None)
[3372]1260            if study_course_obj is None:
1261                msg = 'student %s: no study_course object' % student_id
1262                break
1263            level_obj = getattr(study_course_obj,level,None)
1264            if  level_obj is None:
1265                # The only difference to the edit method is that we create a StudentStudyLevel object
1266                try:
1267                    study_course_obj.invokeFactory('StudentStudyLevel',"%s" % level)
1268                    level_obj = getattr(context,"%s" % level)
1269                except:
1270                    continue
1271            level_obj.getContent().edit(mapping = mapping)
1272            level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
1273            if level_review_state != "closed":
1274                wftool.doActionFor(level_obj,'close')
1275            break
1276        return key,msg,mapping
1277    ###)
1278
1279    def edit(self,mapping): ###(
1280        "edit student levels"
1281        wftool = self.portal_workflow
[3988]1282        logger = logging.getLogger('WAeUPImport.StudentStudyLevelImport.edit')
[3372]1283        students_folder = self.portal_url.getPortalObject().campus.students
1284        student_id = mapping.get('id',None)
1285        matric_no = mapping.get('matric_no',None)
1286        key = ''
1287        msg = ''
1288        while True:
1289            result = self.findStudent('create',student_id=student_id,matric_no=matric_no)
1290            msg = result['msg']
1291            if msg:
1292                break
1293            student_record = result['student_record']
1294            student_id = student_record.id
1295            mapping['id'] = student_id
[3381]1296            session = mapping.get('session','')
1297            level = key = mapping.get('code','')
[3372]1298            #import pdb;pdb.set_trace()
1299            if not level.isdigit():
1300                msg = 'student %s: imported level is empty' % (student_id,)
1301                break
[3381]1302            study_course_obj = getattr(getattr(students_folder,student_id),'study_course',None)
[3372]1303            if study_course_obj is None:
1304                msg = 'student %s: no study_course object' % student_id
1305                break
1306            level_obj = getattr(study_course_obj,level,None)
1307            if  level_obj is None:
1308                msg = 'student %s: no study_level object for level %s' % (student_id,level)
1309                break
1310            level_obj.getContent().edit(mapping = mapping)
1311            break
1312        return key,msg,mapping
1313    ###)
[3381]1314###)
[3372]1315
[3172]1316class VerdictImport(WAeUPImport):###(
1317    """ VerdictImport """
1318    name = "verdict"
1319    plural_name = "%ss" % name
[3977]1320    commit_after = 1000
[3172]1321    required_modes = ('create','edit')
[3249]1322
[3372]1323    def create(self,mapping): ###(
[3243]1324        "edit student verdicts and create StudentStudyLevel object if not existent"
1325        wftool = self.portal_workflow
[3988]1326        logger = logging.getLogger('WAeUPImport.VerdictImport.create')
[3243]1327        students_folder = self.portal_url.getPortalObject().campus.students
1328        student_id = mapping.get('id',None)
1329        matric_no = mapping.get('matric_no',None)
1330        editable_keys = mapping.keys()
[3372]1331        key = ''
[3243]1332        while True:
[3372]1333            result = self.findStudent('create',student_id=student_id,matric_no=matric_no)
1334            #student_record,msg = self.getStudentRecord(mapping)
1335            msg = result['msg']
1336            if msg:
1337                break
1338            student_record = result['student_record']
1339            student_id = student_record.id
1340            mapping['id'] = student_id
1341            d = {}
1342            #import pdb;pdb.set_trace()
1343            any_change = False
1344            #special treatment for StudentStudyLevel
1345            current_session = d['session'] = mapping.get('current_session','')
1346            if current_session and student_record.session != current_session:
1347                msg = 'student %s: imported session %s does not match current_session %s' % (student_id,
1348                                                                                            current_session,
1349                                                                                            student_record.session)
1350                break
1351            current_level = mapping.get('current_level','')
1352            if not current_level.isdigit():
1353                msg = 'student %s: imported level is empty' % (student_id,)
1354                break
1355            if current_level and student_record.level != current_level:
1356                msg = 'student %s: imported level %s does not match current_level %s' % (student_id,
1357                                                                                        current_level,
1358                                                                                        student_record.level)
1359                break
1360            student_review_state =  student_record.review_state
1361            if student_review_state == 'deactivated':
1362                msg = "student %s in review_state %s" % (student_id, student_review_state)
1363                break
1364            if student_review_state not in ('courses_validated','returning'):
1365                msg = "student %s in wrong review_state %s" % (student_id, student_review_state)
1366                break
1367            student_obj = getattr(students_folder,student_id)
1368            # f2t = self.field2types_student
1369            study_course_obj = getattr(student_obj,'study_course',None)
1370            if study_course_obj is None:
1371                msg = 'student %s: no study_course object' % student_id
1372                break
1373            level_obj = getattr(study_course_obj,current_level,None)
1374
1375            if  level_obj is None:
1376                # The only difference to the edit method is that we create a StudentStudyLevel object
1377                try:
1378                    study_course_obj.invokeFactory('StudentStudyLevel',"%s" % current_level)
1379                    level_obj = getattr(context,"%s" % current_level)
1380                    level_obj.portal_workflow.doActionFor(level,'open')
1381                except:
1382                    continue
1383                #msg = 'student %s: no study_level object for level %s' % (student_id,
1384                #                                                                current_level)
1385                #break
1386
1387            verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
1388
1389            #if verdict == student_record.verdict:
1390            #    msg = 'student %s: verdict already set to %s' % (student_id,
1391            #                                                            verdict)
1392
1393            level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
1394            if level_review_state != "closed":
1395                wftool.doActionFor(level_obj,'close')
1396                # msg = 'student %s: level %s is not closed' % (student_id,
1397                #                                                      current_level)
1398
1399            study_course_obj.getContent().edit(mapping = d)
1400            level_obj.getContent().edit(mapping = d)
1401            if student_review_state != "returning":
1402                wftool.doActionFor(student_obj,'return')
1403            # try:
1404            #     wftool.doActionFor(level_obj,'close')
1405            # except:
1406            #     pass
1407            break
1408        return student_id,msg,mapping
1409    ###)
1410
[3207]1411
[3372]1412    def edit(self,mapping): ###(
1413        "edit student verdicts"
1414        wftool = self.portal_workflow
[3988]1415        logger = logging.getLogger('WAeUPImport.VerdictImport.edit')
[3372]1416        students_folder = self.portal_url.getPortalObject().campus.students
1417        student_id = mapping.get('id',None)
1418        matric_no = mapping.get('matric_no',None)
1419        editable_keys = mapping.keys()
1420        key = ''
1421        while True:
1422            result = self.findStudent('edit',student_id=student_id,matric_no=matric_no)
1423            #student_record,msg = self.getStudentRecord(mapping)
1424            msg = result['msg']
1425            if msg:
1426                break
1427            student_record = result['student_record']
1428            key_used = result['key_used']
[3375]1429            if key_used in editable_keys:
[3374]1430                editable_keys.remove(key_used)
[3372]1431            student_id = student_record.id
1432            mapping['id'] = student_id
1433            d = {}
1434            #import pdb;pdb.set_trace()
1435            any_change = False
1436            #special treatment for StudentStudyLevel
1437            current_session = d['session'] = mapping.get('current_session','')
1438            if current_session and student_record.session != current_session:
1439                msg = 'student %s: imported session %s does not match current_session %s' % (student_id,
1440                                                                                            current_session,
1441                                                                                            student_record.session)
1442                break
1443            current_level = mapping.get('current_level','')
1444            if not current_level.isdigit():
1445                msg = 'student %s: imported level is empty' % (student_id,)
1446                break
1447            if current_level and student_record.level != current_level:
1448                msg = 'student %s: imported level %s does not match current_level %s' % (student_id,
1449                                                                                        current_level,
1450                                                                                        student_record.level)
1451                break
1452            student_review_state =  student_record.review_state
1453            if student_review_state == 'deactivated':
1454                msg = "student %s in review_state %s" % (student_id, student_review_state)
1455                break
1456            if student_review_state not in ('courses_validated','returning'):
1457                msg = "student %s in wrong review_state %s" % (student_id, student_review_state)
1458                break
1459            student_obj = getattr(students_folder,student_id)
1460            # f2t = self.field2types_student
1461            study_course_obj = getattr(student_obj,'study_course',None)
1462            if study_course_obj is None:
1463                msg = 'student %s: no study_course object' % student_id
1464                break
[5513]1465            verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
1466
[3372]1467            level_obj = getattr(study_course_obj,current_level,None)
1468            if  level_obj is None:
[5516]1469                pass
[5513]1470                #msg = 'student %s: no study_level object for level %s' % (student_id,current_level)
1471                #break
[5516]1472            else:
[5513]1473                level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
1474                if level_review_state != "closed":
1475                    self.waeup_tool.changeWorkflowState(level_obj, 'closed')
1476                level_obj.getContent().edit(mapping = d)
1477            study_course_obj.getContent().edit(mapping = d)           
[3372]1478            if student_review_state != "returning":
[5183]1479                self.waeup_tool.changeStudentState(student_obj, 'returning')
[3372]1480            break
1481        return student_id,msg,mapping
1482    ###)
1483
[3988]1484   
1485   
1486class PaymentImport(WAeUPImport):###(
1487    """ PaymentImport """
1488    name = "payment"
1489    plural_name = "%ss" % name
[8226]1490    commit_after = 2000
[3988]1491    required_modes = ('create',)
1492
1493    def create(self,mapping): ###(
1494        "create payment object"
[3172]1495        wftool = self.portal_workflow
[3988]1496        logger = logging.getLogger('WAeUPImport.PaymentImport.create')
[3172]1497        students_folder = self.portal_url.getPortalObject().campus.students
1498        student_id = mapping.get('id',None)
[3988]1499        order_id = key= mapping.get('order_id',None)
1500        payment_type = mapping.get('type',None)
[3172]1501        editable_keys = mapping.keys()
[3372]1502        key = ''
[3988]1503        msg = ''
[3172]1504        while True:
[3988]1505            result = self.findStudent('create',student_id=student_id)
1506            msg = result['msg']
1507            if msg:
1508                break           
1509            if payment_type == 'sc':
1510                hyphen = order_id.rfind('-')
1511                if not hyphen > -1:
1512                    msg = '%s: wrong order_id of sc payment' % student_id
[3172]1513                    break
[3988]1514                payment_object_id = 'p' + order_id[hyphen+1:]
1515            elif payment_type == 'online':
1516                payment_object_id = 'p' + order_id[6:]
[3172]1517            else:
[3988]1518                msg = '%s: no payment type defined' % student_id
[3172]1519                break
[3988]1520            student_record = result['student_record']
[3172]1521            student_id = student_record.id
[3988]1522
[3172]1523            mapping['id'] = student_id
[3988]1524            payments_folder = getattr(getattr(students_folder,student_id),'payments',None)
1525            if payments_folder is None:
1526                msg = '%s: no payments folder' % student_id
[3172]1527                break
[3988]1528            if getattr(payments_folder,payment_object_id,False):
1529                msg = '%s: payment object with id %s exists' % (student_id,payment_object_id)
[3172]1530                break
[3988]1531            try:
1532                #import pdb;pdb.set_trace()
1533                payments_folder.invokeFactory('Payment',"%s" % payment_object_id)
1534                payment_obj = getattr(payments_folder,"%s" % payment_object_id)
1535            except:
1536                msg = '%s: payment object %s cannot be created' % (student_id,payment_object_id)
[3172]1537                break
[3988]1538            payment_obj.getContent().edit(mapping = mapping)
1539            wftool.doActionFor(payment_obj,'close')
[3172]1540            break
[3988]1541        return key,msg,mapping
[3172]1542    ###)
[3988]1543   
1544   
[9232]1545
[5039]1546    def remove(self,mapping):
1547        order_id = mapping.get('order_id')
[9232]1548        student_id = mapping.get('id')
[5039]1549        msg = ''
1550        while True:
[9232]1551            if not student_id and order_id:
1552                msg = 'student_id or order_id wrong'
1553                break
1554            students_folder = self.portal_url.getPortalObject().campus.students
1555            payments_folder = getattr(getattr(students_folder,student_id),'payments',None)
1556            payment_object_id = 'p' + order_id[6:]
1557
1558            if payments_folder is None:
1559                msg = '%s: no payments folder' % student_id
1560                break
1561            if not getattr(payments_folder,payment_object_id,False):
1562                msg = '%s: payment object with id %s does not exist' % (student_id,payment_object_id)
1563                break
1564
1565            payments_folder.manage_delObjects((payment_object_id),)
1566
[9233]1567            #if self.payments_catalog.getRecordByKey(order_id) is None:
1568            #    msg =  "no payment record with order_id %(order_id)s" % vars()
1569            #    break
1570            #self.payments_catalog.deleteRecord(order_id)
[5039]1571            break
1572        return order_id,msg,mapping       
1573   
1574   
[3372]1575###)
Note: See TracBrowser for help on using the repository browser.