source: WAeUP_SRP/base/WAeUPTables.py @ 2942

Last change on this file since 2942 was 2926, checked in by Henrik Bettermann, 17 years ago

second trial to fix payment records and objects

  • Property svn:keywords set to Id
File size: 55.0 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 2926 2007-12-12 21:50:08Z henrik $
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
519    def __init__(self,name=None):
520        if name ==  None:
521            name = self.name
522        WAeUPTable.__init__(self, name)
523
524
525    def searchAndSetRecord(self, uid, student_id,prefix):
526
527        # The following line must be activated after resetting the
528        # the portal_pins table. This is to avoid duplicate entries
529        # and disable duplicate payments.
530
531        #student_id = student_id.upper()
532
533        #records = self.searchResults(student = student_id)
534        #if len(records) > 0 and prefix in ('CLR','APP'):
535        #    for r in records:
536        #        if r.pin != uid and r.prefix_batch.startswith(prefix):
537        #            return -2
538        records = self.searchResults({"%s" % self.key : uid})
539        if len(records) > 1:
540            # Can not happen, but anyway...
541            raise ValueError("More than one record with uid %s" % uid)
542        if len(records) == 0:
543            return -1,None
544        record = records[0]
545        if record.student == "":
546            record_data = {}
547            for field in self.schema() + self.indexes():
548                record_data[field] = getattr(record, field)
549            # Add the updated data:
550            record_data['student'] = student_id
551            try:
552                self.catalog_object(dict2ob(record_data), uid)
553                return 1,record
554            except ConflictError:
555                return 2,record
556        if record.student.upper() != student_id.upper():
557            return 0,record
558        if record.student.upper() == student_id.upper():
559            return 2,record
560        return -3,record
561InitializeClass(PinTable)
562###)
563
564class PumeResultsTable(WAeUPTable): ###(
565
566    meta_type = 'WAeUP PumeResults Tool'
567    name = "portal_pumeresults"
568    key = "jamb_reg_no"
569    def __init__(self,name=None):
570        if name ==  None:
571            name = self.name
572        WAeUPTable.__init__(self, name)
573
574
575InitializeClass(PumeResultsTable)
576
577###)
578
579class ApplicantsCatalog(WAeUPTable): ###(
580
581    meta_type = 'WAeUP Applicants Catalog'
582    name = "applicants_catalog"
583    key = "reg_no"
584    security = ClassSecurityInfo()
585    #export_keys = (
586    #               "reg_no",
587    #               "status",
588    #               "lastname",
589    #               "sex",
590    #               "date_of_birth",
591    #               "lga",
592    #               "email",
593    #               "phone",
594    #               "passport",
595    #               "entry_mode",
596    #               "pin",
597    #               "screening_type",
598    #               "registration_date",
599    #               "testdate",
600    #               "application_date",
601    #               "screening_date",
602    #               "faculty",
603    #               "department",
604    #               "course1",
605    #               "course2",
606    #               "course3",
607    #               "eng_score",
608    #               "subj1",
609    #               "subj1score",
610    #               "subj2",
611    #               "subj2score",
612    #               "subj3",
613    #               "subj3score",
614    #               "aggregate",
615    #               "course_admitted",
616    #               )
617
618    def __init__(self,name=None):
619        if name ==  None:
620            name = self.name
621        WAeUPTable.__init__(self, name)
622
623    security.declareProtected(ModifyPortalContent,"new_importCSV")###(
624    def new_importCSV(self,filename="JAMB_data",
625                  schema_id="application",
626                  layout_id="import_application",
627                  mode='add'):
628        """ import JAMB data """
629        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
630        pm = self.portal_membership
631        member = pm.getAuthenticatedMember()
632        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
633        lock_fn = "%s/import/%s_import_lock" % (i_home,filename)
634        import_fn = "%s/import/%s.csv" % (i_home,filename)
635        if mode not in ('add','edit'):
636            logger.info("invalid mode: %s" % mode)
637        if os.path.exists(lock_fn):
638            logger.info("import of %(import_fn)s already in progress" % vars())
639            return
640        lock_file = open(lock_fn,"w")
641        lock_file.write("%(current)s \n" % vars())
642        lock_file.close()
643        invalid_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
644        duplicate_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
645        stool = getToolByName(self, 'portal_schemas')
646        ltool = getToolByName(self, 'portal_layouts')
647        schema = stool._getOb(schema_id)
648        if schema is None:
649            em = 'No such schema %s' % schema_id
650            logger.error(em)
651            return
652        for postfix in ('_import',''):
653            layout_name = "%(layout_id)s%(postfix)s" % vars()
654            if hasattr(ltool,layout_name):
655                break
656        layout = ltool._getOb(layout_name)
657        if layout is None:
658            em = 'No such layout %s' % layout_id
659            logger.error(em)
660            return
661        try:
662            csv_file = csv.DictReader(open(import_fn,"rb"))
663        except:
664            em = 'Error reading %s.csv' % filename
665            logger.error(em)
666            return
667        d = self._import_new(csv_items,schema,layout,mode,logger)
668        imported = []
669        edited = []
670        duplicates = []
671        not_found = []
672        if len(d['valid_records']) > 0:
673            for record in d['valid_records']:
674                #import pdb;pdb.set_trace()
675                if mode == "add":
676                    try:
677                        self.addRecord(**dict(record.items()))
678                        imported.append(**dict(record.items()))
679                        logger.info("added %s" % record.items())
680                    except ValueError:
681                        dupplicate.append(**dict(record.items()))
682                        logger.info("duplicate %s" % record.items())
683                elif mode == "edit":
684                    try:
685                        self.modifyRecord(**dict(record.items()))
686                        edited.append(**dict(record.items()))
687                        logger.info("edited %s" % record.items())
688                    except KeyError:
689                        not_found.append(**dict(record.items()))
690                        logger.info("not found %s" % record.items())
691        invalid = d['invalid_records']
692        for itype in ("imported","edited","not_found","duplicate","invalid"):
693            outlist = locals[itype]
694            if len(outlist):
695                d = {}
696                for k in outlist[0].keys():
697                    d[k] = k
698                outlist[0] = d
699                outfile = open("file_name_%s" % itype,'w')
700                csv.DictWriter(outfile,outlist[0].keys()).writerows(outlist)
701                logger.info("wrote %(itype)s records to %(, written to %(not_imported_fn)s" % d)
702###)
703
704    security.declareProtected(ModifyPortalContent,"importCSV")###(
705    def importCSV(self,filename="JAMB_data",
706                  schema_id="application",
707                  layout_id="application_pce",
708                  mode='add'):
709        """ import JAMB data """
710        stool = getToolByName(self, 'portal_schemas')
711        ltool = getToolByName(self, 'portal_layouts')
712        schema = stool._getOb(schema_id)
713        if schema is None:
714            em = 'No such schema %s' % schema_id
715            logger.error(em)
716            return
717        layout = ltool._getOb(layout_id)
718        if layout is None:
719            em = 'No such layout %s' % layout_id
720            logger.error(em)
721            return
722        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
723        d = self._import_old(filename,schema,layout,mode,logger)
724        if len(d['valid_records']) > 0:
725            for record in d['valid_records']:
726                #import pdb;pdb.set_trace()
727                if mode == "add":
728                    self.addRecord(**dict(record.items()))
729                    logger.info("added %s" % record.items())
730                elif mode == "edit":
731                    self.modifyRecord(**dict(record.items()))
732                    logger.info("edited %s" % record.items())
733                else:
734                    logger.info("invalid mode: %s" % mode)
735        logger.info("%(mode)sed %(imported)d records, invalid written to %(not_imported_fn)s" % d)
736    ###)
737
738InitializeClass(ApplicantsCatalog)
739
740###)
741
742class StudentsCatalog(WAeUPTable): ###(
743    security = ClassSecurityInfo()
744
745    meta_type = 'WAeUP Students Catalog'
746    name = "students_catalog"
747    key = "id"
748    affected_types = {   ###(
749                      'StudentApplication':
750                      {'id': 'application',
751                       'fields':
752                       ('jamb_reg_no',
753                        'entry_mode',
754                        #'entry_level',
755                        'entry_session',
756                       )
757                      },
758                      'StudentClearance':
759                      {'id': 'clearance',
760                       'fields':
761                       ('matric_no',
762                        'lga',
763                       )
764                      },
765                      'StudentPersonal':
766                      {'id': 'personal',
767                       'fields':
768                       ('name',
769                        'sex',
770                        'perm_address',
771                        'email',
772                        'phone',
773                       )
774                      },
775                      'StudentStudyCourse':
776                      {'id': 'study_course',
777                       'fields':
778                       ('course', # study_course
779                        'faculty', # from certificate
780                        'department', # from certificate
781                        'end_level', # from certificate
782                        'level', # current_level
783                        'mode',  # current_mode
784                        'session', # current_session
785                        'verdict', # current_verdict
786                       )
787                      },
788                     }
789    ###)
790
791    def __init__(self,name=None):
792        if name ==  None:
793            name = self.name
794        WAeUPTable.__init__(self, name)
795        return
796
797    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
798        """ clears the whole enchilada """
799        self._catalog.clear()
800
801        if REQUEST and RESPONSE:
802            RESPONSE.redirect(
803              URL1 +
804              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
805
806    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
807        """ clear the catalog, then re-index everything """
808
809        elapse = time.time()
810        c_elapse = time.clock()
811
812        pgthreshold = self._getProgressThreshold()
813        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
814        self.refreshCatalog(clear=1, pghandler=handler)
815
816        elapse = time.time() - elapse
817        c_elapse = time.clock() - c_elapse
818
819        RESPONSE.redirect(
820            URL1 +
821            '/manage_catalogAdvanced?manage_tabs_message=' +
822            urllib.quote('Catalog Updated \n'
823                         'Total time: %s\n'
824                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
825    ###)
826
827    def fill_certificates_dict(self): ###(
828        "return certificate data in  dict"
829        certificates_brains = self.portal_catalog(portal_type ='Certificate')
830        d = {}
831        for cb in certificates_brains:
832            certificate_doc = cb.getObject().getContent()
833            cb_path = cb.getPath().split('/')
834            ld = {}
835            ld['faculty'] = cb_path[-4]
836            ld['department'] = cb_path[-3]
837            ld['end_level'] = getattr(certificate_doc,'end_level','999')
838            d[cb.getId] = ld
839        return d
840    ###)
841
842    def get_from_doc_department(self,doc,cached_data={}): ###(
843        "return the students department"
844        if doc is None:
845            return None
846        if cached_data.has_key(doc.study_course):
847            return cached_data[doc.study_course]['department']
848        certificate_res = self.portal_catalog(id = doc.study_course)
849        if len(certificate_res) != 1:
850            return None
851        return certificate_res[0].getPath().split('/')[-3]
852
853    def get_from_doc_faculty(self,doc,cached_data={}):
854        "return the students faculty"
855        if doc is None:
856            return None
857        if cached_data.has_key(doc.study_course):
858            return cached_data[doc.study_course]['faculty']
859        certificate_res = self.portal_catalog(id = doc.study_course)
860        if len(certificate_res) != 1:
861            return None
862        return certificate_res[0].getPath().split('/')[-4]
863
864    def get_from_doc_end_level(self,doc,cached_data={}):
865        "return the students end_level"
866        if doc is None:
867            return None
868        if cached_data.has_key(doc.study_course):
869            return cached_data[doc.study_course]['end_level']
870        certificate_res = self.portal_catalog(id = doc.study_course)
871        if len(certificate_res) != 1:
872            return None
873        return getattr(certificate_res[0].getObject().getContent(),'end_level','unknown')
874
875    def get_from_doc_level(self,doc,cached_data={}):
876        "return the students level"
877        if doc is None:
878            return None
879        return getattr(doc,'current_level',None)
880
881    def get_from_doc_mode(self,doc,cached_data={}):
882        "return the students mode"
883        if doc is None:
884            return None
885        cm = getattr(doc,'current_mode',None)
886        return cm
887
888
889    def get_from_doc_session(self,doc,cached_data={}):
890        "return the students current_session"
891        if doc is None:
892            return None
893        return getattr(doc,'current_session',None)
894
895    def get_from_doc_entry_session(self,doc,cached_data={}):
896        "return the students entry_session"
897        if doc is None:
898            return None
899        es = getattr(doc,'entry_session',None)
900        if es is not None and len(es) == 2:
901            return es
902        try:
903            digit = int(doc.jamb_reg_no[0])
904        except:
905            return "-1"
906        if digit < 8:
907            return "0%c" % doc.jamb_reg_no[0]
908        return "9%c" % doc.jamb_reg_no[0]
909
910    def get_from_doc_course(self,doc,cached_data={}):
911        "return the students study_course"
912        if doc is None:
913            return None
914        return getattr(doc,'study_course',None)
915
916    def get_from_doc_name(self,doc,cached_data={}):
917        "return the students name from the personal"
918        if doc is None:
919            return None
920        return "%s %s %s" % (doc.firstname,doc.middlename,doc.lastname)
921
922    def get_from_doc_verdict(self,doc,cached_data={}):
923        "return the students study_course"
924        if doc is None:
925            return None
926        return getattr(doc,'current_verdict',None)
927    ###)
928
929    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
930        if isinstance(name, str):
931            name = (name,)
932        reindextypes = {}
933        reindex_special = []
934        for n in name:
935            if n in ("review_state","registered_courses"):
936                reindex_special.append(n)
937            else:
938                for pt in self.affected_types.keys():
939                    if n in self.affected_types[pt]['fields']:
940                        if reindextypes.has_key(pt):
941                            reindextypes[pt].append(n)
942                        else:
943                            reindextypes[pt]= [n]
944                        break
945        cached_data = {}
946        if set(name).intersection(set(('faculty','department','end_level'))):
947            cached_data = self.fill_certificates_dict()
948        students = self.portal_catalog(portal_type="Student")
949        if hasattr(self,'portal_catalog_real'):
950            aq_portal = self.portal_catalog_real.evalAdvancedQuery
951        else:
952            aq_portal = self.portal_catalog.evalAdvancedQuery
953        num_objects = len(students)
954        if pghandler:
955            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
956        noattr = set(('StudentClearance','StudentPersonal')) & set(reindextypes.keys())
957        #import pdb;pdb.set_trace()
958        for i in xrange(num_objects):
959            if pghandler: pghandler.report(i)
960            student_brain = students[i]
961            student_object = student_brain.getObject()
962            # query = Eq('path',student_brain.getPath())
963            # sub_brains_list = aq_portal(query)
964            # sub_brains = {}
965            # for sub_brain in sub_brains_list:
966            #     sub_brains[sub_brain.portal_type] = sub_brain
967            # student_path = student_brain.getPath()
968            data = {}
969            modified = False
970            sid = data['id'] = student_brain.getId
971            if reindex_special and 'review_state' in reindex_special:
972                modified = True
973                data['review_state'] = student_brain.review_state
974            sub_objects = False
975            for pt in reindextypes.keys():
976                modified = True
977                try:
978                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
979                    #doc = sub_brains[pt].getObject().getContent()
980                    # path = "%s/%s" % (student_path,self.affected_types[pt]['id'])
981                    # doc = self.unrestrictedTraverse(path).getContent()
982                    sub_objects = True
983                except:
984                    continue
985                for field in set(name).intersection(self.affected_types[pt]['fields']):
986                    if hasattr(self,'get_from_doc_%s' % field):
987                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
988                                                                              cached_data=cached_data)
989                    else:
990                        data[field] = getattr(doc,field)
991            if not sub_objects and noattr:
992                import_res = self.returning_import(id = sid)
993                if not import_res:
994                    continue
995                import_record = import_res[0]
996                data['matric_no'] = import_record.matric_no
997                data['sex'] = import_record.Sex == 'F'
998                data['name'] = "%s %s %s" % (import_record.Firstname,
999                                             import_record.Middlename,
1000                                             import_record.Lastname)
1001                data['jamb_reg_no'] = import_record.Entryregno
1002            #if reindex_special and 'registered_courses' in reindex_special:
1003            #    try:
1004            #        study_course = getattr(student_object,"study_course")
1005            #        level_ids = study_course.objectIds()
1006            #    except:
1007            #        continue
1008            #    if not level_ids:
1009            #        continue
1010            #    modified = True
1011            #    level_ids.sort()
1012            #    course_ids = getattr(study_course,level_ids[-1]).objectIds()
1013            #    courses = []
1014            #    for c in course_ids:
1015            #        if c.endswith('_co'):
1016            #            courses.append(c[:-3])
1017            #        else:
1018            #            courses.append(c)
1019            #    data['registered_courses'] = courses
1020            if modified:
1021                self.modifyRecord(**data)
1022        if pghandler: pghandler.finish()
1023    ###)
1024
1025    def refreshCatalog(self, clear=0, pghandler=None): ###(
1026        """ re-index everything we can find """
1027        students_folder = self.portal_url.getPortalObject().campus.students
1028        if clear:
1029            self._catalog.clear()
1030        students = self.portal_catalog(portal_type="Student")
1031        num_objects = len(students)
1032        cached_data = self.fill_certificates_dict()
1033        if pghandler:
1034            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1035        for i in xrange(num_objects):
1036            if pghandler: pghandler.report(i)
1037            student_brain = students[i]
1038            spath = student_brain.getPath()
1039            student_object = student_brain.getObject()
1040            data = {}
1041            sid = data['id'] = student_brain.getId
1042            data['review_state'] = student_brain.review_state
1043            sub_objects = False
1044            for pt in self.affected_types.keys():
1045                modified = True
1046                try:
1047                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
1048                    sub_objects = True
1049                except:
1050                    #from pdb import set_trace;set_trace()
1051                    continue
1052                for field in self.affected_types[pt]['fields']:
1053                    if hasattr(self,'get_from_doc_%s' % field):
1054                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
1055                                                                              cached_data=cached_data)
1056                    else:
1057                        data[field] = getattr(doc,field,None)
1058            if not sub_objects:
1059                import_res = self.returning_import(id = sid)
1060                if not import_res:
1061                    continue
1062                import_record = import_res[0]
1063                data['matric_no'] = import_record.matric_no
1064                data['sex'] = import_record.Sex == 'F'
1065                data['name'] = "%s %s %s" % (import_record.Firstname,
1066                                             import_record.Middlename,
1067                                             import_record.Lastname)
1068                data['jamb_reg_no'] = import_record.Entryregno
1069            self.addRecord(**data)
1070        if pghandler: pghandler.finish()
1071    ###)
1072
1073    security.declarePrivate('notify_event_listener') ###(
1074    def notify_event_listener(self,event_type,object,infos):
1075        "listen for events"
1076        if not infos.has_key('rpath'):
1077            return
1078        pt = getattr(object,'portal_type',None)
1079        mt = getattr(object,'meta_type',None)
1080        students_catalog = self
1081        data = {}
1082        if pt == 'Student' and\
1083           mt == 'CPS Proxy Folder' and\
1084           event_type.startswith('workflow'):
1085            data['id'] = object.getId()
1086            data['review_state'] = self.portal_workflow.getInfoFor(object,'review_state',None)
1087            students_catalog.modifyRecord(**data)
1088            return
1089        rpl = infos['rpath'].split('/')
1090        if pt == 'Student' and mt == 'CPS Proxy Folder':
1091            student_id = object.id
1092            if event_type == "sys_add_object":
1093                try:
1094                    self.addRecord(id = student_id)
1095                except ValueError:
1096                    pass
1097                return
1098            elif event_type == 'sys_del_object':
1099                self.deleteRecord(student_id)
1100        if pt not in self.affected_types.keys():
1101            return
1102        if event_type not in ('sys_modify_object'):
1103            return
1104        if mt == 'CPS Proxy Folder':
1105            return
1106        for field in self.affected_types[pt]['fields']:
1107            if hasattr(self,'get_from_doc_%s' % field):
1108                data[field] = getattr(self,'get_from_doc_%s' % field)(object)
1109            else:
1110                data[field] = getattr(object,field)
1111        data['id'] = rpl[2]
1112        self.modifyRecord(**data)
1113    ###)
1114
1115
1116InitializeClass(StudentsCatalog)
1117
1118###)
1119
1120class CoursesCatalog(WAeUPTable): ###(
1121    security = ClassSecurityInfo()
1122
1123    meta_type = 'WAeUP Courses Catalog'
1124    name =  "courses_catalog"
1125    key = "code"
1126    def __init__(self,name=None):
1127        if name ==  None:
1128            name =  self.name
1129        WAeUPTable.__init__(self, name)
1130
1131    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
1132        """ clear the catalog, then re-index everything """
1133
1134        elapse = time.time()
1135        c_elapse = time.clock()
1136
1137        pgthreshold = self._getProgressThreshold()
1138        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
1139        self.refreshCatalog(clear=1, pghandler=handler)
1140
1141        elapse = time.time() - elapse
1142        c_elapse = time.clock() - c_elapse
1143
1144        RESPONSE.redirect(
1145            URL1 +
1146            '/manage_catalogAdvanced?manage_tabs_message=' +
1147            urllib.quote('Catalog Updated \n'
1148                         'Total time: %s\n'
1149                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
1150    ###)
1151
1152    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
1153        if isinstance(name, str):
1154            name = (name,)
1155        courses = self.portal_catalog(portal_type="Course")
1156        num_objects = len(courses)
1157        if pghandler:
1158            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1159        for i in xrange(num_objects):
1160            if pghandler: pghandler.report(i)
1161            course_brain = courses[i]
1162            course_object = course_brain.getObject()
1163            pl = course_brain.getPath().split('/')
1164            data = {}
1165            cid = data[self.key] = course_brain.getId
1166            data['faculty'] = pl[-4]
1167            data['department'] = pl[-3]
1168            doc = course_object.getContent()
1169            for field in name:
1170                if field not in (self.key,'faculty','department'):
1171                    data[field] = getattr(doc,field)
1172            self.modifyRecord(**data)
1173        if pghandler: pghandler.finish()
1174    ###)
1175
1176    def refreshCatalog(self, clear=0, pghandler=None): ###(
1177        """ re-index everything we can find """
1178        if clear:
1179            self._catalog.clear()
1180        courses = self.portal_catalog(portal_type="Course")
1181        num_objects = len(courses)
1182        if pghandler:
1183            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1184        #from pdb import set_trace;set_trace()
1185        for i in xrange(num_objects):
1186            if pghandler: pghandler.report(i)
1187            course_brain = courses[i]
1188            course_doc = course_brain.getObject().getContent()
1189            pl = course_brain.getPath().split('/')
1190            data = {}
1191            for field in self.schema():
1192                data[field] = getattr(course_doc,field,None)
1193            data[self.key] = course_brain.getId
1194            ai = pl.index('academics')
1195            data['faculty'] = pl[ai +1]
1196            data['department'] = pl[ai +2]
1197            if clear:
1198                self.addRecord(**data)
1199            else:
1200                self.modifyRecord(**data)
1201        if pghandler: pghandler.finish()
1202    ###)
1203
1204    security.declarePrivate('notify_event_listener') ###(
1205    def notify_event_listener(self,event_type,object,infos):
1206        "listen for events"
1207        if not infos.has_key('rpath'):
1208            return
1209        pt = getattr(object,'portal_type',None)
1210        mt = getattr(object,'meta_type',None)
1211        if pt != 'Course':
1212            return
1213        data = {}
1214        rpl = infos['rpath'].split('/')
1215        if event_type not in ("sys_add_object","sys_modify_object","sys_del_object"):
1216            return
1217        course_id = object.getId()
1218        data[self.key] = course_id
1219        if event_type == "sys_add_object" and mt == 'CPS Proxy Folder':
1220            try:
1221                self.addRecord(**data)
1222            except ValueError:
1223                return
1224            course_id = object.getId()
1225            doc = object.getContent()
1226            if doc is None:
1227                return
1228            for field in self.schema():
1229                data[field] = getattr(doc,field,None)
1230            data[self.key] = course_id
1231            ai = rpl.index('academics')
1232            data['faculty'] = rpl[ai +1]
1233            data['department'] = rpl[ai +2]
1234            self.modifyRecord(**data)
1235            return
1236        if event_type == "sys_del_object":
1237            self.deleteRecord(course_id)
1238            return
1239        if event_type == "sys_modify_object" and mt == 'Course':
1240            #from pdb import set_trace;set_trace()
1241            for field in self.schema():
1242                data[field] = getattr(object,field,None)
1243            course_id = object.aq_parent.getId()
1244            data[self.key] = course_id
1245            ai = rpl.index('academics')
1246            data['faculty'] = rpl[ai +1]
1247            data['department'] = rpl[ai +2]
1248            self.modifyRecord(**data)
1249    ###)
1250
1251
1252InitializeClass(CoursesCatalog)
1253###)
1254
1255class CourseResults(WAeUPTable): ###(
1256    security = ClassSecurityInfo()
1257
1258    meta_type = 'WAeUP Results Catalog'
1259    name = "course_results"
1260    key = "key" #student_id + level + course_id
1261    def __init__(self,name=None):
1262        if name ==  None:
1263            name = self.name
1264        WAeUPTable.__init__(self, name)
1265        self._queue = []
1266
1267    def addMultipleRecords(self, records): ###(
1268        """add many records"""
1269        added_keys = []
1270        for data in records:
1271            uid = key = "%(student_id)s|%(level_id)s|%(course_id)s" % data
1272            data['%s' % self.key] = uid
1273            res = self.searchResults({"%s" % self.key : uid})
1274            if len(res) > 0:
1275                raise ValueError("More than one record with uid %s" % uid)
1276            self.catalog_object(dict2ob(data), uid=uid)
1277        return uid
1278    ###)
1279
1280    def deleteResultsHere(self,level_id,student_id): ###(
1281        #import pdb;pdb.set_trace()
1282        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1283        course_results = self.course_results.evalAdvancedQuery(query)
1284        for result in course_results:
1285            self.deleteRecord(result.key)
1286    ###)
1287
1288    def moveResultsHere(self,level,student_id): ###(
1289        #import pdb;pdb.set_trace()
1290        level_id = level.getId()
1291        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1292        course_results = self.course_results.evalAdvancedQuery(query)
1293        existing_courses = [cr.code for cr in course_results]
1294        to_delete = []
1295        for code,obj in level.objectItems():
1296            to_delete.append(code)
1297            carry_over = False
1298            if code.endswith('_co'):
1299                carry_over = True
1300                code  = code[:-3]
1301            if code in existing_courses:
1302                continue
1303            course_result_doc = obj.getContent()
1304            data = {}
1305            course_id = code
1306            for field in self.schema():
1307                data[field] = getattr(course_result_doc,field,'')
1308            data['key'] = key = "%(student_id)s|%(level_id)s|%(course_id)s" % vars()
1309            data['student_id'] = student_id
1310            data['level_id'] = level_id
1311            session_id = self.getLevelSession(level.getContent(),student_id,level_id)
1312            data['session_id'] = session_id
1313            #data['queue_status'] = OBJECT_CREATED
1314            data['code'] = course_id
1315            data['carry_over'] = carry_over
1316            self.catalog_object(dict2ob(data), uid=key)
1317        level.manage_delObjects(to_delete)
1318    ###)
1319
1320    def getCourses(self,student_id,level_id): ###(
1321        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1322        course_results = self.course_results.evalAdvancedQuery(query)
1323        carry_overs = []
1324        normal1 = []
1325        normal2 = []
1326        normal3 = []
1327        total_credits = 0
1328        gpa = 0
1329        for brain in course_results:
1330            d = {}
1331
1332            for field in self.schema():
1333                d[field] = getattr(brain,field,'')
1334
1335            d['weight'] = ''
1336            d['grade'] = ''
1337            d['score'] = ''
1338
1339            if str(brain.credits).isdigit():
1340                credits = int(brain.credits)
1341                total_credits += credits
1342                score = getattr(brain,'score',0)
1343                if score and str(score).isdigit() and int(score) > 0:
1344                    score = int(score)
1345                    grade,weight = self.getGradesFromScore(score)
1346                    gpa += weight * credits
1347                    d['weight'] = weight
1348                    d['grade'] = grade
1349                    d['score'] = score
1350            d['coe'] = ''
1351            if brain.core_or_elective:
1352                d['coe'] = 'Core'
1353            elif brain.core_or_elective == False:
1354                d['coe'] = 'Elective'
1355            id = code = d['id'] = brain.code
1356            d['code'] = code
1357            res = self.courses_catalog.evalAdvancedQuery(Eq('code',code))
1358            if res:
1359                course = res[0]
1360                d['title'] = course.title
1361                # The courses_catalog contains strings and integers in its semester field.
1362                # Maybe this can be fixed by reindexing the catalog. The schema of course says 'CPS Int Field'.
1363                d['semester'] = str(course.semester)
1364            else:
1365                d['title'] = "Course has been removed from course list"
1366                d['semester'] = ''
1367            if brain.carry_over:
1368                d['coe'] = 'CO'
1369                carry_overs.append(d)
1370            else:
1371                if d['semester'] == '1':
1372                    normal1.append(d)
1373
1374                elif d['semester'] == '2':
1375                    normal2.append(d)
1376                else:
1377                    normal3.append(d)
1378        #normal.sort(cmp=lambda x,y: cmp("%(semester)s%(code)s" % x,
1379        #                                "%(semester)s%(code)s" % y))
1380        carry_overs.sort(cmp=lambda x,y: cmp("%(semester)s%(code)s" % x,
1381                                             "%(semester)s%(code)s" % y))
1382        return total_credits,gpa,carry_overs,normal1,normal2,normal3
1383    ###)
1384
1385InitializeClass(CourseResults)
1386###)
1387
1388class OnlinePaymentsImport(WAeUPTable): ###(
1389
1390    meta_type = 'WAeUP Online Payment Transactions'
1391    name = "online_payments_import"
1392    key = "order_id"
1393    def __init__(self,name=None):
1394        if name ==  None:
1395            name = self.name
1396        WAeUPTable.__init__(self, name)
1397
1398
1399InitializeClass(OnlinePaymentsImport)
1400###)
1401
1402class ReturningImport(WAeUPTable): ###(
1403
1404    meta_type = 'Returning Import Table'
1405    name = "returning_import"
1406    key = "matric_no"
1407    def __init__(self,name=None):
1408        if name ==  None:
1409            name = self.name
1410        WAeUPTable.__init__(self, name)
1411
1412
1413InitializeClass(ReturningImport)
1414###)
1415
1416class ResultsImport(WAeUPTable): ###(
1417
1418    meta_type = 'Results Import Table'
1419    name = "results_import"
1420    key = "key"
1421    def __init__(self,name=None):
1422        if name ==  None:
1423            name = self.name
1424        WAeUPTable.__init__(self, name)
1425
1426
1427InitializeClass(ResultsImport)
1428
1429###)
1430
1431class PaymentsCatalog(WAeUPTable): ###(
1432    security = ClassSecurityInfo()
1433
1434    meta_type = 'WAeUP Payments Catalog'
1435    name = "payments_catalog"
1436    key = "order_id"
1437    def __init__(self,name=None):
1438        if name ==  None:
1439            name = self.name
1440        WAeUPTable.__init__(self, name)
1441
1442
1443    security.declarePrivate('notify_event_listener') ###(
1444    def notify_event_listener(self,event_type,object,infos):
1445        "listen for events"
1446        if not infos.has_key('rpath'):
1447            return
1448        pt = getattr(object,'portal_type',None)
1449        mt = getattr(object,'meta_type',None)
1450        data = {}
1451        if pt != 'Payment':
1452            return
1453        if mt == 'CPS Proxy Folder':
1454            return # is handled only for the real object
1455        if event_type == 'sys_del_object':
1456            self.deleteRecord(object.order_id)
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        #import pdb;pdb.set_trace()
1463        student_id = rpl[-4]
1464        data['student_id'] = student_id
1465        modified = False
1466        try:
1467            self.modifyRecord(**data)
1468            modified = True
1469        except KeyError:
1470            #logger = logging.getLogger('WAeUPTables.PaymentsCatalog.%s' % self.__name__)
1471            #logger.info("could not modify entry for %(student_id)s with %(order_id)s" % data)
1472            pass
1473        if not modified:
1474            try:
1475                self.addRecord(**data)
1476            except:
1477                logger = logging.getLogger('WAeUPTables.PaymentsCatalog.%s' % self.__name__)
1478                logger.info("could not add or modify entry for %(student_id)s with %(order_id)s" % data)
1479        ###)
1480
1481
1482InitializeClass(PaymentsCatalog)
1483
1484###)
1485
1486# BBB:
1487AccomodationTable = AccommodationTable
Note: See TracBrowser for help on using the repository browser.