source: WAeUP_SRP/trunk/WAeUPImport.py @ 4558

Last change on this file since 4558 was 4558, checked in by Henrik Bettermann, 15 years ago

restore the final accommodation object when reimporting the data into the alumni portal

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