source: WAeUP_SRP/base/WAeUPTables.py @ 2495

Last change on this file since 2495 was 2460, checked in by joachim, 17 years ago

fix refreshlevel + add_course_result

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