source: WAeUP_SRP/trunk/WAeUPImport.py @ 5510

Last change on this file since 5510 was 5504, checked in by Henrik Bettermann, 14 years ago

catch wrong reg_transition (admitted and returning) to avoid editing of import files

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