source: WAeUP_SRP/base/WAeUPTables.py @ 2849

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

add sort_id, additional fields in payment

  • Property svn:keywords set to Id
File size: 54.4 KB
Line 
1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 AixtraWare <http://aixtraware.de>
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: WAeUPTables.py 2845 2007-12-03 21:14:20Z joachim $
20
21from zope.interface import implements
22from Globals import InitializeClass
23from Products.ZCatalog.ZCatalog import ZCatalog
24from Products.ZCatalog.ProgressHandler import ZLogHandler
25from AccessControl import ClassSecurityInfo
26from Products.CMFCore.permissions import ModifyPortalContent
27from Products.CMFCore.utils import getToolByName
28from Products.CMFCore.CatalogTool import CatalogTool
29from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
30from Products.CPSSchemas.DataStructure import DataStructure
31from Products.CPSSchemas.DataModel import DataModel
32from Products.AdvancedQuery import Eq, Between, Le,In
33import urllib
34import DateTime,time
35import csv,re
36import logging
37import Globals
38p_home = Globals.package_home(globals())
39i_home = Globals.INSTANCE_HOME
40
41ADDING_SHEDULED = "adding_sheduled"
42OBJECT_CREATED = "object_created"
43NOT_OCCUPIED = 'not_occupied'
44
45from interfaces import IWAeUPTable
46
47class AttributeHolder(object):
48    pass
49
50def dict2ob(dict):
51    ob = AttributeHolder()
52    for key, value in dict.items():
53        setattr(ob, key, value)
54    return ob
55
56class WAeUPTable(ZCatalog): ###(
57
58    implements(IWAeUPTable)
59    security = ClassSecurityInfo()
60    meta_type = None
61
62    def __init__(self,name=None):
63        if name ==  None:
64            name = self.name
65        ZCatalog.__init__(self,name)
66
67    def refreshCatalog(self, clear=0, pghandler=None): ###(
68        """ don't refresh for a normal table """
69
70        if self.REQUEST and self.REQUEST.RESPONSE:
71            self.REQUEST.RESPONSE.redirect(
72              URL1 +
73              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20refresh%20not%20implemented')
74
75###)
76
77    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None): ###(
78        """ clears the whole enchilada """
79
80        #if REQUEST and RESPONSE:
81        #    RESPONSE.redirect(
82        #      URL1 +
83        #      '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Clearing%20disabled')
84
85        self._catalog.clear()
86        if REQUEST and RESPONSE:
87            RESPONSE.redirect(
88              URL1 +
89              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20cleared')
90
91###)
92
93    def record2dict(self,fields,record): ###(
94        d = {}
95        for key in fields:
96            v = getattr(record, key, None)
97            if key == 'sex':
98                if v:
99                    v = 'F'
100                else:
101                    v = 'M'
102                d[key] = v
103            elif v:
104                if key == 'lga':
105                    v = self.portal_vocabularies.local_gov_areas.get(v)
106                elif key == 'aos':
107                    v = self.portal_vocabularies.aos.get(v)
108                d[key] = v
109            else:
110                d[key] = ''
111        return d
112
113###)
114
115    def addRecord(self, **data): ###(
116        # The uid is the same as "bed".
117        uid = data[self.key]
118        res = self.searchResults({"%s" % self.key : uid})
119        if len(res) > 0:
120            raise ValueError("More than one record with uid %s" % uid)
121        self.catalog_object(dict2ob(data), uid=uid)
122        return uid
123
124###)
125
126    def deleteRecord(self, uid):
127        self.uncatalog_object(uid)
128
129    def getRecordByKey(self,key):
130        if not key:
131            return None
132        res = self.evalAdvancedQuery(Eq(self.key,key))
133        if res:
134            return res[0]
135        return None
136
137    def searchAndSetRecord(self, **data):
138        raise NotImplemented
139
140    def modifyRecord(self, record=None, **data): ###(
141        #records = self.searchResults(uid=uid)
142        uid = data[self.key]
143        if record is None:
144            records = self.searchResults({"%s" % self.key : uid})
145            if len(records) > 1:
146                # Can not happen, but anyway...
147                raise ValueError("More than one record with uid %s" % uid)
148            if len(records) == 0:
149                raise KeyError("No record for uid %s" % uid)
150            record = records[0]
151        record_data = {}
152        for field in self.schema() + self.indexes():
153            record_data[field] = getattr(record, field)
154        # Add the updated data:
155        record_data.update(data)
156        self.catalog_object(dict2ob(record_data), uid)
157
158###)
159
160    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
161        if isinstance(name, str):
162            name =  (name,)
163        paths = self._catalog.uids.items()
164        i = 0
165        #import pdb;pdb.set_trace()
166        for p,rid in paths:
167            i += 1
168            metadata = self.getMetadataForRID(rid)
169            record_data = {}
170            for field in name:
171                record_data[field] = metadata.get(field)
172            uid = metadata.get(self.key)
173            self.catalog_object(dict2ob(record_data), uid, idxs=name,
174                                update_metadata=0)
175
176###)
177
178    security.declareProtected(ModifyPortalContent,"exportAllRecords") ###(
179    def exportAllRecords(self):
180        "export a WAeUPTable"
181        #import pdb;pdb.set_trace()
182        fields = [field for field in self.schema()]
183        format = ','.join(['"%%(%s)s"' % fn for fn in fields])
184        csv = []
185        csv.append(','.join(['"%s"' % fn for fn in fields]))
186        for uid in self._catalog.uids:
187            records = self.searchResults({"%s" % self.key : uid})
188            if len(records) > 1:
189                # Can not happen, but anyway...
190                raise ValueError("More than one record with uid %s" % uid)
191            if len(records) == 0:
192                raise KeyError("No record for uid %s" % uid)
193            rec = records[0]
194            csv.append(format % rec)
195        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
196        open("%s/import/%s-%s.csv" % (i_home,self.getId(),current),"w+").write('\n'.join(csv))
197
198###)
199
200    security.declareProtected(ModifyPortalContent,"dumpAll")###(
201    def dumpAll(self):
202        """dump all data in the table to a csv"""
203        member = self.portal_membership.getAuthenticatedMember()
204        logger = logging.getLogger('WAeUPTables.dump_%s' % self.__name__)
205        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
206        export_file = "%s/export/%s_%s.csv" % (i_home,self.__name__,current,)
207        print export_file
208        res_list = []
209        lines = []
210        if hasattr(self,"export_keys"):
211            fields = self.export_keys
212        else:
213            fields = []
214            for f in self.schema():
215                fields.append(f)
216        headline = ','.join(fields)
217        #open(export_file,"a").write(headline +'\n')
218        out = open(export_file,"wb")
219        out.write(headline +'\n')
220        out.close()
221        out = open(export_file,"a")
222        csv_writer = csv.DictWriter(out,fields,)
223        #format = '"%(' + ')s","%('.join(fields) + ')s"'
224        records = self()
225        nr2export = len(records)
226        logger.info('%s starts dumping, %s records to export' % (member,nr2export))
227        chunk = 2000
228        total = 0
229        start = DateTime.DateTime().timeTime()
230        start_chunk = DateTime.DateTime().timeTime()
231        for record in records:
232            not_all = False
233            d = self.record2dict(fields,record)
234            lines.append(d)
235            total += 1
236            if total and not total % chunk or total == len(records):
237                #open(export_file,"a").write('\n'.join(lines) +'\n')
238                csv_writer.writerows(lines)
239                anz = len(lines)
240                logger.info("wrote %(anz)d  total written %(total)d" % vars())
241                end_chunk = DateTime.DateTime().timeTime()
242                duration = end_chunk-start_chunk
243                per_record = duration/anz
244                till_now = end_chunk - start
245                avarage_per_record = till_now/total
246                estimated_end = DateTime.DateTime(start + avarage_per_record * nr2export)
247                estimated_end = estimated_end.strftime("%H:%M:%S")
248                logger.info('%(duration)4.1f, %(per_record)4.3f,end %(estimated_end)s' % vars())
249                start_chunk = DateTime.DateTime().timeTime()
250                lines = []
251        end = DateTime.DateTime().timeTime()
252        logger.info('total time %6.2f m' % ((end-start)/60))
253        import os
254        filename, extension = os.path.splitext(export_file)
255        from subprocess import call
256        msg = "wrote %(total)d records to %(export_file)s" % vars()
257        #try:
258        #    retcode = call('gzip %s' % (export_file),shell=True)
259        #    if retcode == 0:
260        #        msg = "wrote %(total)d records to %(export_file)s.gz" % vars()
261        #except OSError, e:
262        #    retcode = -99
263        #    logger.info("zip failed with %s" % e)
264        logger.info(msg)
265        args = {'portal_status_message': msg}
266        #url = self.REQUEST.get('URL1') + '?' + urlencode(args)
267        url = self.REQUEST.get('URL2')
268        return self.REQUEST.RESPONSE.redirect(url)
269    ###)
270
271    security.declarePrivate("_import_old") ###(
272    def _import_old(self,filename,schema,layout, mode,logger):
273        "import data from csv"
274        import transaction
275        import random
276        pm = self.portal_membership
277        member = pm.getAuthenticatedMember()
278        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
279        import_fn = "%s/import/%s.csv" % (i_home,filename)
280        imported_fn = "%s/import/%s_imported%s.csv" % (i_home,filename,current)
281        not_imported_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
282        start = True
283        tr_count = 1
284        total_imported = 0
285        total_not_imported = 0
286        total = 0
287        iname =  "%s" % filename
288        not_imported = []
289        imported = []
290        valid_records = []
291        invalid_records = []
292        d = {}
293        d['mode'] = mode
294        d['imported'] = total_imported
295        d['not_imported'] = total_not_imported
296        d['valid_records'] = valid_records
297        d['invalid_records'] = invalid_records
298        d['import_fn'] = import_fn
299        d['imported_fn'] = imported_fn
300        d['not_imported_fn'] = not_imported_fn
301        if schema is None:
302            em = 'No schema specified'
303            logger.error(em)
304            return d
305        if layout is None:
306            em = 'No layout specified'
307            logger.error(em)
308            return d
309        validators = {}
310        for widget in layout.keys():
311            try:
312                validators[widget] = layout[widget].validate
313            except AttributeError:
314                logger.info('%s has no validate attribute' % widget)
315                return d
316        # if mode == 'edit':
317        #     importer = self.importEdit
318        # elif mode == 'add':
319        #     importer = self.importAdd
320        # else:
321        #     importer = None
322        try:
323            items = csv.DictReader(open(import_fn,"rb"),
324                                   dialect="excel",
325                                   skipinitialspace=True)
326        except:
327            em = 'Error reading %s.csv' % filename
328            logger.error(em)
329            return d
330        #import pdb;pdb.set_trace()
331        for item in items:
332            if start:
333                start = False
334                logger.info('%s starts import from %s.csv' % (member,filename))
335                #import_keys = [k for k in item.keys() if not k.startswith('ignore')]
336                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb"),
337                                   dialect="excel",
338                                   skipinitialspace=True).next()
339                import_keys = [k for k in attrs if not (k.startswith('ignore') or k.isupper())]
340                diff2schema = set(import_keys).difference(set(schema.keys()))
341                diff2layout = set(import_keys).difference(set(layout.keys()))
342                if diff2layout:
343                    em = "not ignorable key(s) %s found in heading" % diff2layout
344                    logger.info(em)
345                    return d
346                s = ','.join(['"%s"' % fn for fn in import_keys])
347                open(not_imported_fn,"a").write(s + ',"Error"'+ '\n')
348                #s = '"id",' + s
349                open(imported_fn,"a").write(s + '\n')
350                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
351                format_error = format + ',"%(Error)s"'
352                #format = '"%(id)s",'+ format
353                adapters = [MappingStorageAdapter(schema, item)]
354            dm = DataModel(item, adapters,context=self)
355            ds = DataStructure(data=item,datamodel=dm)
356            error_string = ""
357            #import pdb;pdb.set_trace()
358            for k in import_keys:
359                if not validators[k](ds,mode=mode):
360                    error_string += " %s : %s" % (k,ds.getError(k))
361            # if not error_string and importer:
362            #     item.update(dm)
363            #     item['id'],error = importer(item)
364            #     if error:
365            #         error_string += error
366            if error_string:
367                item['Error'] = error_string
368                invalid_records.append(dm)
369                not_imported.append(format_error % item)
370                total_not_imported += 1
371            else:
372                em = format % item
373                valid_records.append(dm)
374                imported.append(em)
375                #logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
376                tr_count += 1
377                total_imported += 1
378            total += 1
379        if len(imported) > 0:
380            open(imported_fn,"a").write('\n'.join(imported))
381        if len(not_imported) > 0:
382            open(not_imported_fn,"a").write('\n'.join(not_imported))
383        #em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
384        d['imported'] = total_imported
385        d['not_imported'] = total_not_imported
386        d['valid_records'] = valid_records
387        d['invalid_records'] = invalid_records
388        d['imported_fn'] = imported_fn
389        d['not_imported_fn'] = not_imported_fn
390        #logger.info(em)
391        return d
392    ###)
393
394    security.declarePrivate("_import") ###(
395    def _import_new(self,csv_items,schema, layout, mode,logger):
396        "import data from csv.Dictreader Instance"
397        start = True
398        tr_count = 1
399        total_imported = 0
400        total_not_imported = 0
401        total = 0
402        iname =  "%s" % filename
403        not_imported = []
404        valid_records = []
405        invalid_records = []
406        duplicate_records = []
407        d = {}
408        d['mode'] = mode
409        d['valid_records'] = valid_records
410        d['invalid_records'] = invalid_records
411        d['invalid_records'] = duplicate_records
412        # d['import_fn'] = import_fn
413        # d['imported_fn'] = imported_fn
414        # d['not_imported_fn'] = not_imported_fn
415        validators = {}
416        for widget in layout.keys():
417            try:
418                validators[widget] = layout[widget].validate
419            except AttributeError:
420                logger.info('%s has no validate attribute' % widget)
421                return d
422        for item in csv_items:
423            if start:
424                start = False
425                logger.info('%s starts import from %s.csv' % (member,filename))
426                #import_keys = [k for k in item.keys() if not k.startswith('ignore')]
427                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
428                import_keys = [k for k in attrs if not (k.startswith('ignore') or k.isupper())]
429                diff2schema = set(import_keys).difference(set(schema.keys()))
430                diff2layout = set(import_keys).difference(set(layout.keys()))
431                if diff2layout:
432                    em = "not ignorable key(s) %s found in heading" % diff2layout
433                    logger.info(em)
434                    return d
435                # s = ','.join(['"%s"' % fn for fn in import_keys])
436                # open(not_imported_fn,"a").write(s + ',"Error"'+ '\n')
437                # #s = '"id",' + s
438                # open(imported_fn,"a").write(s + '\n')
439                # format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
440                # format_error = format + ',"%(Error)s"'
441                # #format = '"%(id)s",'+ format
442                adapters = [MappingStorageAdapter(schema, item)]
443            dm = DataModel(item, adapters,context=self)
444            ds = DataStructure(data=item,datamodel=dm)
445            error_string = ""
446            for k in import_keys:
447                if not validators[k](ds,mode=mode):
448                    error_string += " %s : %s" % (k,ds.getError(k))
449            if error_string:
450                item['Error'] = error_string
451                #invalid_records.append(dm)
452                invalid_records.append(item)
453                total_not_imported += 1
454            else:
455                em = format % item
456                valid_records.append(dm)
457                #logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
458                tr_count += 1
459                total_imported += 1
460            total += 1
461        # if len(imported) > 0:
462        #     open(imported_fn,"a").write('\n'.join(imported))
463        # if len(not_imported) > 0:
464        #     open(not_imported_fn,"a").write('\n'.join(not_imported))
465        #em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
466        d['imported'] = total_imported
467        d['not_imported'] = total_not_imported
468        d['valid_records'] = valid_records
469        d['invalid_records'] = invalid_records
470        return d
471    ###)
472
473    security.declarePublic("missingValue")###(
474    def missingValue(self):
475        from Missing import MV
476        return MV
477    ###)
478###)
479
480class AccommodationTable(WAeUPTable): ###(
481
482    meta_type = 'WAeUP Accommodation Tool'
483    name = "portal_accommodation"
484    key = "bed"
485    def __init__(self,name=None):
486        if name ==  None:
487            name = self.name
488        WAeUPTable.__init__(self, name)
489   
490    def searchAndReserveBed(self, student_id,bed_type):
491        #records = self.searchResults({'student' : student_id})
492        import pdb;pdb.set_trace()
493        records = self.evalAdvancedQuery(Eq('student',student_id))
494        if len(records) > 0:
495            return -1,"Student with Id %s already booked bed %s." % (student_id,records[0].bed)
496
497        #records = [r for r in self.searchResults({'bed_type' : bed_type}) if not r.student]
498        query = Eq('bed_type',bed_type) & Eq('student',NOT_OCCUPIED)
499        records = self.evalAdvancedQuery(query,sortSpecs=('sort_id','bed'))
500        if len(records) == 0:
501            return -2,"No bed available"
502        rec = records[0]
503        self.modifyRecord(bed=rec.bed,student=student_id)
504        s_logger = logging.getLogger('WAeUPTables.AccommodationTable.searchAndReserveBed')
505        s_logger.info('%s reserved bed %s' % (student_id,rec.bed))
506        return 1,rec.bed
507
508
509InitializeClass(AccommodationTable)
510
511###)
512
513class PinTable(WAeUPTable): ###(
514    from ZODB.POSException import ConflictError
515    meta_type = 'WAeUP Pin Tool'
516    name = "portal_pins"
517    key = 'pin'
518    def __init__(self,name=None):
519        if name ==  None:
520            name = self.name
521        WAeUPTable.__init__(self, name)
522
523
524    def searchAndSetRecord(self, uid, student_id,prefix):
525
526        # The following line must be activated after resetting the
527        # the portal_pins table. This is to avoid duplicate entries
528        # and disable duplicate payments.
529
530        #student_id = student_id.upper()
531
532        #records = self.searchResults(student = student_id)
533        #if len(records) > 0 and prefix in ('CLR','APP'):
534        #    for r in records:
535        #        if r.pin != uid and r.prefix_batch.startswith(prefix):
536        #            return -2
537        records = self.searchResults({"%s" % self.key : uid})
538        if len(records) > 1:
539            # Can not happen, but anyway...
540            raise ValueError("More than one record with uid %s" % uid)
541        if len(records) == 0:
542            return -1,None
543        record = records[0]
544        if record.student == "":
545            record_data = {}
546            for field in self.schema() + self.indexes():
547                record_data[field] = getattr(record, field)
548            # Add the updated data:
549            record_data['student'] = student_id
550            try:
551                self.catalog_object(dict2ob(record_data), uid)
552                return 1,record
553            except ConflictError:
554                return 2,record
555        if record.student.upper() != student_id.upper():
556            return 0,record
557        if record.student.upper() == student_id.upper():
558            return 2,record
559        return -3,record
560InitializeClass(PinTable)
561###)
562
563class PumeResultsTable(WAeUPTable): ###(
564
565    meta_type = 'WAeUP PumeResults Tool'
566    name = "portal_pumeresults"
567    key = "jamb_reg_no"
568    def __init__(self,name=None):
569        if name ==  None:
570            name = self.name
571        WAeUPTable.__init__(self, name)
572
573
574InitializeClass(PumeResultsTable)
575
576###)
577
578class ApplicantsCatalog(WAeUPTable): ###(
579
580    meta_type = 'WAeUP Applicants Catalog'
581    name = "applicants_catalog"
582    key = "reg_no"
583    security = ClassSecurityInfo()
584    #export_keys = (
585    #               "reg_no",
586    #               "status",
587    #               "lastname",
588    #               "sex",
589    #               "date_of_birth",
590    #               "lga",
591    #               "email",
592    #               "phone",
593    #               "passport",
594    #               "entry_mode",
595    #               "pin",
596    #               "screening_type",
597    #               "registration_date",
598    #               "testdate",
599    #               "application_date",
600    #               "screening_date",
601    #               "faculty",
602    #               "department",
603    #               "course1",
604    #               "course2",
605    #               "course3",
606    #               "eng_score",
607    #               "subj1",
608    #               "subj1score",
609    #               "subj2",
610    #               "subj2score",
611    #               "subj3",
612    #               "subj3score",
613    #               "aggregate",
614    #               "course_admitted",
615    #               )
616
617    def __init__(self,name=None):
618        if name ==  None:
619            name = self.name
620        WAeUPTable.__init__(self, name)
621
622    security.declareProtected(ModifyPortalContent,"new_importCSV")###(
623    def new_importCSV(self,filename="JAMB_data",
624                  schema_id="application",
625                  layout_id="import_application",
626                  mode='add'):
627        """ import JAMB data """
628        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
629        pm = self.portal_membership
630        member = pm.getAuthenticatedMember()
631        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
632        lock_fn = "%s/import/%s_import_lock" % (i_home,filename)
633        import_fn = "%s/import/%s.csv" % (i_home,filename)
634        if mode not in ('add','edit'):
635            logger.info("invalid mode: %s" % mode)
636        if os.path.exists(lock_fn):
637            logger.info("import of %(import_fn)s already in progress" % vars())
638            return
639        lock_file = open(lock_fn,"w")
640        lock_file.write("%(current)s \n" % vars())
641        lock_file.close()
642        invalid_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
643        duplicate_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
644        stool = getToolByName(self, 'portal_schemas')
645        ltool = getToolByName(self, 'portal_layouts')
646        schema = stool._getOb(schema_id)
647        if schema is None:
648            em = 'No such schema %s' % schema_id
649            logger.error(em)
650            return
651        for postfix in ('_import',''):
652            layout_name = "%(layout_id)s%(postfix)s" % vars()
653            if hasattr(ltool,layout_name):
654                break
655        layout = ltool._getOb(layout_name)
656        if layout is None:
657            em = 'No such layout %s' % layout_id
658            logger.error(em)
659            return
660        try:
661            csv_file = csv.DictReader(open(import_fn,"rb"))
662        except:
663            em = 'Error reading %s.csv' % filename
664            logger.error(em)
665            return
666        d = self._import_new(csv_items,schema,layout,mode,logger)
667        imported = []
668        edited = []
669        duplicates = []
670        not_found = []
671        if len(d['valid_records']) > 0:
672            for record in d['valid_records']:
673                #import pdb;pdb.set_trace()
674                if mode == "add":
675                    try:
676                        self.addRecord(**dict(record.items()))
677                        imported.append(**dict(record.items()))
678                        logger.info("added %s" % record.items())
679                    except ValueError:
680                        dupplicate.append(**dict(record.items()))
681                        logger.info("duplicate %s" % record.items())
682                elif mode == "edit":
683                    try:
684                        self.modifyRecord(**dict(record.items()))
685                        edited.append(**dict(record.items()))
686                        logger.info("edited %s" % record.items())
687                    except KeyError:
688                        not_found.append(**dict(record.items()))
689                        logger.info("not found %s" % record.items())
690        invalid = d['invalid_records']
691        for itype in ("imported","edited","not_found","duplicate","invalid"):
692            outlist = locals[itype]
693            if len(outlist):
694                d = {}
695                for k in outlist[0].keys():
696                    d[k] = k
697                outlist[0] = d
698                outfile = open("file_name_%s" % itype,'w')
699                csv.DictWriter(outfile,outlist[0].keys()).writerows(outlist)
700                logger.info("wrote %(itype)s records to %(, written to %(not_imported_fn)s" % d)
701###)
702
703    security.declareProtected(ModifyPortalContent,"importCSV")###(
704    def importCSV(self,filename="JAMB_data",
705                  schema_id="application",
706                  layout_id="application_pce",
707                  mode='add'):
708        """ import JAMB data """
709        stool = getToolByName(self, 'portal_schemas')
710        ltool = getToolByName(self, 'portal_layouts')
711        schema = stool._getOb(schema_id)
712        if schema is None:
713            em = 'No such schema %s' % schema_id
714            logger.error(em)
715            return
716        layout = ltool._getOb(layout_id)
717        if layout is None:
718            em = 'No such layout %s' % layout_id
719            logger.error(em)
720            return
721        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
722        d = self._import_old(filename,schema,layout,mode,logger)
723        if len(d['valid_records']) > 0:
724            for record in d['valid_records']:
725                #import pdb;pdb.set_trace()
726                if mode == "add":
727                    self.addRecord(**dict(record.items()))
728                    logger.info("added %s" % record.items())
729                elif mode == "edit":
730                    self.modifyRecord(**dict(record.items()))
731                    logger.info("edited %s" % record.items())
732                else:
733                    logger.info("invalid mode: %s" % mode)
734        logger.info("%(mode)sed %(imported)d records, invalid written to %(not_imported_fn)s" % d)
735    ###)
736
737InitializeClass(ApplicantsCatalog)
738
739###)
740
741class StudentsCatalog(WAeUPTable): ###(
742    security = ClassSecurityInfo()
743
744    meta_type = 'WAeUP Students Catalog'
745    name = "students_catalog"
746    key = "id"
747    affected_types = {   ###(
748                      'StudentApplication':
749                      {'id': 'application',
750                       'fields':
751                       ('jamb_reg_no',
752                        'entry_mode',
753                        #'entry_level',
754                        'entry_session',
755                       )
756                      },
757                      'StudentClearance':
758                      {'id': 'clearance',
759                       'fields':
760                       ('matric_no',
761                        'lga',
762                       )
763                      },
764                      'StudentPersonal':
765                      {'id': 'personal',
766                       'fields':
767                       ('name',
768                        'sex',
769                        'perm_address',
770                        'email',
771                        'phone',
772                       )
773                      },
774                      'StudentStudyCourse':
775                      {'id': 'study_course',
776                       'fields':
777                       ('course', # study_course
778                        'faculty', # from certificate
779                        'department', # from certificate
780                        'end_level', # from certificate
781                        'level', # current_level
782                        'mode',  # current_mode
783                        'session', # current_session
784                        'verdict', # current_verdict
785                       )
786                      },
787                     }
788    ###)
789
790    def __init__(self,name=None):
791        if name ==  None:
792            name = self.name
793        WAeUPTable.__init__(self, name)
794        return
795
796    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
797        """ clears the whole enchilada """
798        self._catalog.clear()
799
800        if REQUEST and RESPONSE:
801            RESPONSE.redirect(
802              URL1 +
803              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
804
805    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
806        """ clear the catalog, then re-index everything """
807
808        elapse = time.time()
809        c_elapse = time.clock()
810
811        pgthreshold = self._getProgressThreshold()
812        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
813        self.refreshCatalog(clear=1, pghandler=handler)
814
815        elapse = time.time() - elapse
816        c_elapse = time.clock() - c_elapse
817
818        RESPONSE.redirect(
819            URL1 +
820            '/manage_catalogAdvanced?manage_tabs_message=' +
821            urllib.quote('Catalog Updated \n'
822                         'Total time: %s\n'
823                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
824    ###)
825
826    def fill_certificates_dict(self): ###(
827        "return certificate data in  dict"
828        certificates_brains = self.portal_catalog(portal_type ='Certificate')
829        d = {}
830        for cb in certificates_brains:
831            certificate_doc = cb.getObject().getContent()
832            cb_path = cb.getPath().split('/')
833            ld = {}
834            ld['faculty'] = cb_path[-4]
835            ld['department'] = cb_path[-3]
836            ld['end_level'] = getattr(certificate_doc,'end_level','999')
837            d[cb.getId] = ld
838        return d
839    ###)
840
841    def get_from_doc_department(self,doc,cached_data={}): ###(
842        "return the students department"
843        if doc is None:
844            return None
845        if cached_data.has_key(doc.study_course):
846            return cached_data[doc.study_course]['department']
847        certificate_res = self.portal_catalog(id = doc.study_course)
848        if len(certificate_res) != 1:
849            return None
850        return certificate_res[0].getPath().split('/')[-3]
851
852    def get_from_doc_faculty(self,doc,cached_data={}):
853        "return the students faculty"
854        if doc is None:
855            return None
856        if cached_data.has_key(doc.study_course):
857            return cached_data[doc.study_course]['faculty']
858        certificate_res = self.portal_catalog(id = doc.study_course)
859        if len(certificate_res) != 1:
860            return None
861        return certificate_res[0].getPath().split('/')[-4]
862
863    def get_from_doc_end_level(self,doc,cached_data={}):
864        "return the students end_level"
865        if doc is None:
866            return None
867        if cached_data.has_key(doc.study_course):
868            return cached_data[doc.study_course]['end_level']
869        certificate_res = self.portal_catalog(id = doc.study_course)
870        if len(certificate_res) != 1:
871            return None
872        return getattr(certificate_res[0].getObject().getContent(),'end_level','unknown')
873
874    def get_from_doc_level(self,doc,cached_data={}):
875        "return the students level"
876        if doc is None:
877            return None
878        return getattr(doc,'current_level',None)
879
880    def get_from_doc_mode(self,doc,cached_data={}):
881        "return the students mode"
882        if doc is None:
883            return None
884        cm = getattr(doc,'current_mode',None)
885        return cm
886
887
888    def get_from_doc_session(self,doc,cached_data={}):
889        "return the students current_session"
890        if doc is None:
891            return None
892        return getattr(doc,'current_session',None)
893
894    def get_from_doc_entry_session(self,doc,cached_data={}):
895        "return the students entry_session"
896        if doc is None:
897            return None
898        es = getattr(doc,'entry_session',None)
899        if es is not None and len(es) == 2:
900            return es
901        try:
902            digit = int(doc.jamb_reg_no[0])
903        except:
904            return "-1"
905        if digit < 8:
906            return "0%c" % doc.jamb_reg_no[0]
907        return "9%c" % doc.jamb_reg_no[0]
908
909    def get_from_doc_course(self,doc,cached_data={}):
910        "return the students study_course"
911        if doc is None:
912            return None
913        return getattr(doc,'study_course',None)
914
915    def get_from_doc_name(self,doc,cached_data={}):
916        "return the students name from the personal"
917        if doc is None:
918            return None
919        return "%s %s %s" % (doc.firstname,doc.middlename,doc.lastname)
920
921    def get_from_doc_verdict(self,doc,cached_data={}):
922        "return the students study_course"
923        if doc is None:
924            return None
925        return getattr(doc,'current_verdict',None)
926    ###)
927
928    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
929        if isinstance(name, str):
930            name = (name,)
931        reindextypes = {}
932        reindex_special = []
933        for n in name:
934            if n in ("review_state","registered_courses"):
935                reindex_special.append(n)
936            else:
937                for pt in self.affected_types.keys():
938                    if n in self.affected_types[pt]['fields']:
939                        if reindextypes.has_key(pt):
940                            reindextypes[pt].append(n)
941                        else:
942                            reindextypes[pt]= [n]
943                        break
944        cached_data = {}
945        if set(name).intersection(set(('faculty','department','end_level'))):
946            cached_data = self.fill_certificates_dict()
947        students = self.portal_catalog(portal_type="Student")
948        if hasattr(self,'portal_catalog_real'):
949            aq_portal = self.portal_catalog_real.evalAdvancedQuery
950        else:
951            aq_portal = self.portal_catalog.evalAdvancedQuery
952        num_objects = len(students)
953        if pghandler:
954            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
955        noattr = set(('StudentClearance','StudentPersonal')) & set(reindextypes.keys())
956        #import pdb;pdb.set_trace()
957        for i in xrange(num_objects):
958            if pghandler: pghandler.report(i)
959            student_brain = students[i]
960            student_object = student_brain.getObject()
961            # query = Eq('path',student_brain.getPath())
962            # sub_brains_list = aq_portal(query)
963            # sub_brains = {}
964            # for sub_brain in sub_brains_list:
965            #     sub_brains[sub_brain.portal_type] = sub_brain
966            # student_path = student_brain.getPath()
967            data = {}
968            modified = False
969            sid = data['id'] = student_brain.getId
970            if reindex_special and 'review_state' in reindex_special:
971                modified = True
972                data['review_state'] = student_brain.review_state
973            sub_objects = False
974            for pt in reindextypes.keys():
975                modified = True
976                try:
977                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
978                    #doc = sub_brains[pt].getObject().getContent()
979                    # path = "%s/%s" % (student_path,self.affected_types[pt]['id'])
980                    # doc = self.unrestrictedTraverse(path).getContent()
981                    sub_objects = True
982                except:
983                    continue
984                for field in set(name).intersection(self.affected_types[pt]['fields']):
985                    if hasattr(self,'get_from_doc_%s' % field):
986                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
987                                                                              cached_data=cached_data)
988                    else:
989                        data[field] = getattr(doc,field)
990            if not sub_objects and noattr:
991                import_res = self.returning_import(id = sid)
992                if not import_res:
993                    continue
994                import_record = import_res[0]
995                data['matric_no'] = import_record.matric_no
996                data['sex'] = import_record.Sex == 'F'
997                data['name'] = "%s %s %s" % (import_record.Firstname,
998                                             import_record.Middlename,
999                                             import_record.Lastname)
1000                data['jamb_reg_no'] = import_record.Entryregno
1001            #if reindex_special and 'registered_courses' in reindex_special:
1002            #    try:
1003            #        study_course = getattr(student_object,"study_course")
1004            #        level_ids = study_course.objectIds()
1005            #    except:
1006            #        continue
1007            #    if not level_ids:
1008            #        continue
1009            #    modified = True
1010            #    level_ids.sort()
1011            #    course_ids = getattr(study_course,level_ids[-1]).objectIds()
1012            #    courses = []
1013            #    for c in course_ids:
1014            #        if c.endswith('_co'):
1015            #            courses.append(c[:-3])
1016            #        else:
1017            #            courses.append(c)
1018            #    data['registered_courses'] = courses
1019            if modified:
1020                self.modifyRecord(**data)
1021        if pghandler: pghandler.finish()
1022    ###)
1023
1024    def refreshCatalog(self, clear=0, pghandler=None): ###(
1025        """ re-index everything we can find """
1026        students_folder = self.portal_url.getPortalObject().campus.students
1027        if clear:
1028            self._catalog.clear()
1029        students = self.portal_catalog(portal_type="Student")
1030        num_objects = len(students)
1031        cached_data = self.fill_certificates_dict()
1032        if pghandler:
1033            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1034        for i in xrange(num_objects):
1035            if pghandler: pghandler.report(i)
1036            student_brain = students[i]
1037            spath = student_brain.getPath()
1038            student_object = student_brain.getObject()
1039            data = {}
1040            sid = data['id'] = student_brain.getId
1041            data['review_state'] = student_brain.review_state
1042            sub_objects = False
1043            for pt in self.affected_types.keys():
1044                modified = True
1045                try:
1046                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
1047                    sub_objects = True
1048                except:
1049                    #from pdb import set_trace;set_trace()
1050                    continue
1051                for field in self.affected_types[pt]['fields']:
1052                    if hasattr(self,'get_from_doc_%s' % field):
1053                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
1054                                                                              cached_data=cached_data)
1055                    else:
1056                        data[field] = getattr(doc,field,None)
1057            if not sub_objects:
1058                import_res = self.returning_import(id = sid)
1059                if not import_res:
1060                    continue
1061                import_record = import_res[0]
1062                data['matric_no'] = import_record.matric_no
1063                data['sex'] = import_record.Sex == 'F'
1064                data['name'] = "%s %s %s" % (import_record.Firstname,
1065                                             import_record.Middlename,
1066                                             import_record.Lastname)
1067                data['jamb_reg_no'] = import_record.Entryregno
1068            self.addRecord(**data)
1069        if pghandler: pghandler.finish()
1070    ###)
1071
1072    security.declarePrivate('notify_event_listener') ###(
1073    def notify_event_listener(self,event_type,object,infos):
1074        "listen for events"
1075        if not infos.has_key('rpath'):
1076            return
1077        pt = getattr(object,'portal_type',None)
1078        mt = getattr(object,'meta_type',None)
1079        students_catalog = self
1080        data = {}
1081        if pt == 'Student' and\
1082           mt == 'CPS Proxy Folder' and\
1083           event_type.startswith('workflow'):
1084            data['id'] = object.getId()
1085            data['review_state'] = self.portal_workflow.getInfoFor(object,'review_state',None)
1086            students_catalog.modifyRecord(**data)
1087            return
1088        rpl = infos['rpath'].split('/')
1089        if pt == 'Student' and mt == 'CPS Proxy Folder':
1090            student_id = object.id
1091            if event_type == "sys_add_object":
1092                try:
1093                    self.addRecord(id = student_id)
1094                except ValueError:
1095                    pass
1096                return
1097            elif event_type == 'sys_del_object':
1098                self.deleteRecord(student_id)
1099        if pt not in self.affected_types.keys():
1100            return
1101        if event_type not in ('sys_modify_object'):
1102            return
1103        if mt == 'CPS Proxy Folder':
1104            return
1105        for field in self.affected_types[pt]['fields']:
1106            if hasattr(self,'get_from_doc_%s' % field):
1107                data[field] = getattr(self,'get_from_doc_%s' % field)(object)
1108            else:
1109                data[field] = getattr(object,field)
1110        data['id'] = rpl[2]
1111        self.modifyRecord(**data)
1112    ###)
1113
1114
1115InitializeClass(StudentsCatalog)
1116
1117###)
1118
1119class CoursesCatalog(WAeUPTable): ###(
1120    security = ClassSecurityInfo()
1121
1122    meta_type = 'WAeUP Courses Catalog'
1123    name =  "courses_catalog"
1124    key = "code"
1125    def __init__(self,name=None):
1126        if name ==  None:
1127            name =  self.name
1128        WAeUPTable.__init__(self, name)
1129
1130    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
1131        """ clear the catalog, then re-index everything """
1132
1133        elapse = time.time()
1134        c_elapse = time.clock()
1135
1136        pgthreshold = self._getProgressThreshold()
1137        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
1138        self.refreshCatalog(clear=1, pghandler=handler)
1139
1140        elapse = time.time() - elapse
1141        c_elapse = time.clock() - c_elapse
1142
1143        RESPONSE.redirect(
1144            URL1 +
1145            '/manage_catalogAdvanced?manage_tabs_message=' +
1146            urllib.quote('Catalog Updated \n'
1147                         'Total time: %s\n'
1148                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
1149    ###)
1150
1151    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
1152        if isinstance(name, str):
1153            name = (name,)
1154        courses = self.portal_catalog(portal_type="Course")
1155        num_objects = len(courses)
1156        if pghandler:
1157            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1158        for i in xrange(num_objects):
1159            if pghandler: pghandler.report(i)
1160            course_brain = courses[i]
1161            course_object = course_brain.getObject()
1162            pl = course_brain.getPath().split('/')
1163            data = {}
1164            cid = data[self.key] = course_brain.getId
1165            data['faculty'] = pl[-4]
1166            data['department'] = pl[-3]
1167            doc = course_object.getContent()
1168            for field in name:
1169                if field not in (self.key,'faculty','department'):
1170                    data[field] = getattr(doc,field)
1171            self.modifyRecord(**data)
1172        if pghandler: pghandler.finish()
1173    ###)
1174
1175    def refreshCatalog(self, clear=0, pghandler=None): ###(
1176        """ re-index everything we can find """
1177        if clear:
1178            self._catalog.clear()
1179        courses = self.portal_catalog(portal_type="Course")
1180        num_objects = len(courses)
1181        if pghandler:
1182            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1183        #from pdb import set_trace;set_trace()
1184        for i in xrange(num_objects):
1185            if pghandler: pghandler.report(i)
1186            course_brain = courses[i]
1187            course_doc = course_brain.getObject().getContent()
1188            pl = course_brain.getPath().split('/')
1189            data = {}
1190            for field in self.schema():
1191                data[field] = getattr(course_doc,field,None)
1192            data[self.key] = course_brain.getId
1193            ai = pl.index('academics')
1194            data['faculty'] = pl[ai +1]
1195            data['department'] = pl[ai +2]
1196            if clear:
1197                self.addRecord(**data)
1198            else:
1199                self.modifyRecord(**data)
1200        if pghandler: pghandler.finish()
1201    ###)
1202
1203    security.declarePrivate('notify_event_listener') ###(
1204    def notify_event_listener(self,event_type,object,infos):
1205        "listen for events"
1206        if not infos.has_key('rpath'):
1207            return
1208        pt = getattr(object,'portal_type',None)
1209        mt = getattr(object,'meta_type',None)
1210        if pt != 'Course':
1211            return
1212        data = {}
1213        rpl = infos['rpath'].split('/')
1214        if event_type not in ("sys_add_object","sys_modify_object","sys_del_object"):
1215            return
1216        course_id = object.getId()
1217        data[self.key] = course_id
1218        if event_type == "sys_add_object" and mt == 'CPS Proxy Folder':
1219            try:
1220                self.addRecord(**data)
1221            except ValueError:
1222                return
1223            course_id = object.getId()
1224            doc = object.getContent()
1225            if doc is None:
1226                return
1227            for field in self.schema():
1228                data[field] = getattr(doc,field,None)
1229            data[self.key] = course_id
1230            ai = rpl.index('academics')
1231            data['faculty'] = rpl[ai +1]
1232            data['department'] = rpl[ai +2]
1233            self.modifyRecord(**data)
1234            return
1235        if event_type == "sys_del_object":
1236            self.deleteRecord(course_id)
1237            return
1238        if event_type == "sys_modify_object" and mt == 'Course':
1239            #from pdb import set_trace;set_trace()
1240            for field in self.schema():
1241                data[field] = getattr(object,field,None)
1242            course_id = object.aq_parent.getId()
1243            data[self.key] = course_id
1244            ai = rpl.index('academics')
1245            data['faculty'] = rpl[ai +1]
1246            data['department'] = rpl[ai +2]
1247            self.modifyRecord(**data)
1248    ###)
1249
1250
1251InitializeClass(CoursesCatalog)
1252###)
1253
1254class CourseResults(WAeUPTable): ###(
1255    security = ClassSecurityInfo()
1256
1257    meta_type = 'WAeUP Results Catalog'
1258    name = "course_results"
1259    key = "key" #student_id + level + course_id
1260    def __init__(self,name=None):
1261        if name ==  None:
1262            name = self.name
1263        WAeUPTable.__init__(self, name)
1264        self._queue = []
1265
1266    def addMultipleRecords(self, records): ###(
1267        """add many records"""
1268        added_keys = []
1269        for data in records:
1270            uid = key = "%(student_id)s|%(level_id)s|%(course_id)s" % data
1271            data['%s' % self.key] = uid
1272            res = self.searchResults({"%s" % self.key : uid})
1273            if len(res) > 0:
1274                raise ValueError("More than one record with uid %s" % uid)
1275            self.catalog_object(dict2ob(data), uid=uid)
1276        return uid
1277    ###)
1278
1279    def deleteResultsHere(self,level_id,student_id): ###(
1280        #import pdb;pdb.set_trace()
1281        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1282        course_results = self.course_results.evalAdvancedQuery(query)
1283        for result in course_results:
1284            self.deleteRecord(result.key)
1285    ###)
1286
1287    def moveResultsHere(self,level,student_id): ###(
1288        #import pdb;pdb.set_trace()
1289        level_id = level.getId()
1290        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1291        course_results = self.course_results.evalAdvancedQuery(query)
1292        existing_courses = [cr.code for cr in course_results]
1293        to_delete = []
1294        for code,obj in level.objectItems():
1295            to_delete.append(code)
1296            carry_over = False
1297            if code.endswith('_co'):
1298                carry_over = True
1299                code  = code[:-3]
1300            if code in existing_courses:
1301                continue
1302            course_result_doc = obj.getContent()
1303            data = {}
1304            course_id = code
1305            for field in self.schema():
1306                data[field] = getattr(course_result_doc,field,'')
1307            data['key'] = key = "%(student_id)s|%(level_id)s|%(course_id)s" % vars()
1308            data['student_id'] = student_id
1309            data['level_id'] = level_id
1310            session_id = self.getLevelSession(level.getContent(),student_id,level_id)
1311            data['session_id'] = session_id
1312            #data['queue_status'] = OBJECT_CREATED
1313            data['code'] = course_id
1314            data['carry_over'] = carry_over
1315            self.catalog_object(dict2ob(data), uid=key)
1316        level.manage_delObjects(to_delete)
1317    ###)
1318
1319    def getCourses(self,student_id,level_id): ###(
1320        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1321        course_results = self.course_results.evalAdvancedQuery(query)
1322        carry_overs = []
1323        normal1 = []
1324        normal2 = []
1325        normal3 = []
1326        total_credits = 0
1327        gpa = 0
1328        for brain in course_results:
1329            d = {}
1330
1331            for field in self.schema():
1332                d[field] = getattr(brain,field,'')
1333
1334            d['weight'] = ''
1335            d['grade'] = ''
1336            d['score'] = ''
1337
1338            if str(brain.credits).isdigit():
1339                credits = int(brain.credits)
1340                total_credits += credits
1341                score = getattr(brain,'score',0)
1342                if score and str(score).isdigit() and int(score) > 0:
1343                    score = int(score)
1344                    grade,weight = self.getGradesFromScore(score)
1345                    gpa += weight * credits
1346                    d['weight'] = weight
1347                    d['grade'] = grade
1348                    d['score'] = score
1349            d['coe'] = ''
1350            if brain.core_or_elective:
1351                d['coe'] = 'Core'
1352            elif brain.core_or_elective == False:
1353                d['coe'] = 'Elective'
1354            id = code = d['id'] = brain.code
1355            d['code'] = code
1356            course = self.courses_catalog.evalAdvancedQuery(Eq('code',code))[0]
1357            d['title'] = course.title
1358
1359            # The courses_catalog contains strings and integers in its semester field.
1360            # Maybe this can be fixed by reindexing the catalog. The schema of course says 'CPS Int Field'.
1361            d['semester'] = str(course.semester)
1362            if brain.carry_over:
1363                d['coe'] = 'CO'
1364                carry_overs.append(d)
1365            else:
1366                if d['semester'] == '1':
1367                    normal1.append(d)
1368
1369                elif d['semester'] == '2':
1370                    normal2.append(d)
1371                else:
1372                    normal3.append(d)
1373        #normal.sort(cmp=lambda x,y: cmp("%(semester)s%(code)s" % x,
1374        #                                "%(semester)s%(code)s" % y))
1375        carry_overs.sort(cmp=lambda x,y: cmp("%(semester)s%(code)s" % x,
1376                                             "%(semester)s%(code)s" % y))
1377        return total_credits,gpa,carry_overs,normal1,normal2,normal3
1378    ###)
1379
1380InitializeClass(CourseResults)
1381###)
1382
1383class OnlinePaymentsImport(WAeUPTable): ###(
1384
1385    meta_type = 'WAeUP Online Payment Transactions'
1386    name = "online_payments_import"
1387    key = "order_id"
1388    def __init__(self,name=None):
1389        if name ==  None:
1390            name = self.name
1391        WAeUPTable.__init__(self, name)
1392
1393
1394InitializeClass(OnlinePaymentsImport)
1395###)
1396
1397class ReturningImport(WAeUPTable): ###(
1398
1399    meta_type = 'Returning Import Table'
1400    name = "returning_import"
1401    key = "matric_no"
1402    def __init__(self,name=None):
1403        if name ==  None:
1404            name = self.name
1405        WAeUPTable.__init__(self, name)
1406
1407
1408InitializeClass(ReturningImport)
1409###)
1410
1411class ResultsImport(WAeUPTable): ###(
1412
1413    meta_type = 'Results Import Table'
1414    name = "results_import"
1415    key = "key"
1416    def __init__(self,name=None):
1417        if name ==  None:
1418            name = self.name
1419        WAeUPTable.__init__(self, name)
1420
1421
1422InitializeClass(ResultsImport)
1423
1424###)
1425
1426class PaymentsCatalog(WAeUPTable): ###(
1427    security = ClassSecurityInfo()
1428
1429    meta_type = 'WAeUP Payments Catalog'
1430    name = "students_catalog"
1431    key = "key"
1432    def __init__(self,name=None):
1433        if name ==  None:
1434            name = self.name
1435        WAeUPTable.__init__(self, name)
1436
1437    security.declarePrivate('notify_event_listener') ###(
1438    def notify_event_listener(self,event_type,object,infos):
1439        "listen for events"
1440        if not infos.has_key('rpath'):
1441            return
1442        pt = getattr(object,'portal_type',None)
1443        mt = getattr(object,'meta_type',None)
1444        data = {}
1445        if pt == 'Payment' and mt == 'CPS Proxy Folder':
1446            order_id = object.id
1447            if event_type == "sys_add_object":
1448                try:
1449                    self.addRecord(order_id = order_id)
1450                except ValueError:
1451                    pass
1452                return
1453            elif event_type == 'sys_del_object':
1454                self.deleteRecord(order_id)
1455        if pt != 'Payment' or mt == 'CPS Proxy Folder':
1456            return
1457        if event_type not in ('sys_modify_object'):
1458            return
1459        for field in self.schema():
1460            data[field] = getattr(object,field)
1461        rpl = infos['rpath'].split('/')
1462        student_id = rpl[-3]
1463        data['student_id'] = student_id
1464        self.modifyRecord(**data)
1465    ###)
1466
1467
1468InitializeClass(PaymentsCatalog)
1469
1470###)
1471
1472# BBB:
1473AccomodationTable = AccommodationTable
Note: See TracBrowser for help on using the repository browser.