source: WAeUP_SRP/trunk/WAeUPTool.py @ 1816

Last change on this file since 1816 was 1816, checked in by Henrik Bettermann, 18 years ago
  • importResults fixed: line readded which had been removed in revion 1700 (don't know why!!)
  • also the link 'Previous Sessions' now works for withdrawn students
  • Property svn:keywords set to Id
File size: 38.5 KB
Line 
1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 The WAeUP group  <http://www.waeup.org>
3# Author: Joachim Schmitz (js@aixtraware.de)
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17# 02111-1307, USA.
18#
19# $Id: WAeUPTool.py 1816 2007-05-24 05:49:27Z henrik $
20"""The WAeUP Tool Box.
21"""
22
23from AccessControl import ClassSecurityInfo
24from Acquisition import aq_inner
25from Acquisition import aq_parent
26from Globals import DTMLFile
27from Globals import InitializeClass
28from OFS.SimpleItem import SimpleItem
29
30from Products.CPSSchemas.DataStructure import DataStructure
31from Products.CPSSchemas.DataModel import DataModel
32from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
33from Products.CMFCore.ActionProviderBase import ActionProviderBase
34from Products.CMFCore.permissions import View
35from Products.ZCatalog.ZCatalog import ZCatalog
36from Products.CMFCore.permissions import ModifyPortalContent
37from Products.CMFCore.utils import UniqueObject
38from Products.CMFCore.URLTool import URLTool
39from Products.CMFCore.utils import getToolByName
40from Students import makeCertificateCode
41from Globals import package_home,INSTANCE_HOME
42p_home = package_home(globals())
43i_home = INSTANCE_HOME
44import DateTime
45import logging
46import transaction
47import csv,re,os
48from Products.AdvancedQuery import Eq, Between, Le,In
49
50def getObject(object,name):
51    if object.hasObject(name):
52        return getattr(object,name)
53    return None
54
55class WAeUPTool(UniqueObject, SimpleItem, ActionProviderBase):
56    """WAeUP tool"""
57
58    id = 'waeup_tool'
59    meta_type = 'WAeUP Tool'
60    _actions = ()
61
62    security = ClassSecurityInfo()
63    security.declareObjectProtected(View)
64
65    manage_options = ( ActionProviderBase.manage_options
66                     + SimpleItem.manage_options
67                     )
68
69    def rwrite(self,s):
70        response = self.REQUEST.RESPONSE
71        response.setHeader('Content-type','text/html; charset=ISO-8859-15')
72        response.write("%s<br />\r\n" % s)
73
74    security.declareProtected(ModifyPortalContent,'openLog')
75    def openLog(self,name):
76        """open a log file"""
77        version = 1
78        path = "%s/log/%s_%d.log" % (i_home,name,version)
79        while os.path.exists(path):
80            version += 1
81            path = "%s/log/%s_%d.log" % (i_home,name,version)
82        log = open(path,"w")
83        return log
84
85    security.declareProtected(ModifyPortalContent,'writeLog')
86    def writeLog(self,logfile,s):
87        """write to the log file"""
88        logfile.write(s)
89
90
91    def generateStudentId(self,letter): ###(
92        import random
93        r = random
94        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
95        if letter == '?':
96            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
97        sid = "%c%d" % (letter,r.randint(99999,1000000))
98        students = self.portal_url.getPortalObject().campus.students
99##        while hasattr(students, sid):
100##            sid = "%c%d" % (letter,r.randint(99999,1000000))
101        while self.students_catalog(id = sid):
102            sid = "%c%d" % (letter,r.randint(99999,1000000))
103        return sid
104    ###)
105
106    def generatePassword(self,s=None): ###(
107        import random
108        r = random
109        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
110        if s is None:
111            s = 'abcdefghklmnpqrstuvwxy23456789'
112        pw = ''
113        while len(pw) < 6:
114            pw += r.choice(s)
115        return pw
116    ###)
117
118    security.declareProtected(ModifyPortalContent,'getCredential') ###(
119    def getCredential(self,student_id):
120        "return a student password"
121        student_entry = getattr(self.portal_directories.students,student_id,None)
122        if student_entry is None:
123            return None
124        return getattr(student_entry,"password","not set")
125    ###)
126
127    security.declarePublic('checkPassword') ###(
128    def checkPassword(self,student_id,password):
129        "return a student password"
130        student_entry = getattr(self.portal_directories.students,student_id,None)
131        if student_entry is None:
132            return False
133        return getattr(student_entry,"password","not set") == password
134    ###)
135
136    security.declarePublic('editPassword') ###(
137    def editPassword(self,student_id,password):
138        "edit a student password"
139        student_entry = getattr(self.portal_directories.students,student_id,None)
140        if student_entry is None:
141            return
142        setattr(student_entry,'password',password)
143    ###)
144
145    security.declareProtected(View,'doCommit') ###(
146    def doCommit(self,logger=None):
147        "commit some transactions"
148        transaction.commit()
149    ###)
150
151    security.declarePublic('loadStudentFoto') ###(
152    def loadStudentFoto(self,student,filename,folder):
153        "return a student passport picture"
154        app_doc = student.application.getContent()
155        #clear = student.clearance
156        #clear_doc = clear.getContent()
157        #matric_no = clear_doc.matric_no.upper()
158        picture1 ="%s/import/%s/%s.jpg" % (i_home,folder,filename)
159        picture2 ="%s/import/%s/%s.JPG" % (i_home,folder,filename)
160        #import pdb;pdb.set_trace()
161        if os.path.exists(picture1):
162            file = open(picture1)
163        elif os.path.exists(picture2):
164            file = open(picture2)
165        else:
166            return "passport picture not found %s" % picture1
167
168        outfile = file.read()
169        app_doc.manage_addFile('passport',
170                               file=outfile,
171                               title="%s.jpg" % matric_no)
172        return "successfully loaded passport picture"
173    ###)
174
175    security.declareProtected(ModifyPortalContent,'createOne') ###(
176    def createOne(self,students_folder,student_brain,letter,commit=False):
177        sid = self.waeup_tool.generateStudentId(letter)
178        students_folder.invokeFactory('Student', sid)
179        student = getattr(students_folder,sid)
180        self.portal_workflow.doActionFor(student,'return')
181        student.manage_setLocalRoles(sid, ['Owner',])
182        matric_no = student_brain.matric_no
183        jamb_reg_no = student_brain.Entryregno
184        self.students_catalog.addRecord(id = sid,
185                                           matric_no = matric_no,
186                                           jamb_reg_no = jamb_reg_no,
187                                           sex = student_brain.Sex == "F",
188                                           name = "%s %s %s" % (student_brain.Firstname,
189                                                                student_brain.Middlename,
190                                                                student_brain.Lastname)
191                                        )
192        if commit:
193            transaction.commit()
194        return sid,jamb_reg_no
195    ###)
196
197    security.declareProtected(ModifyPortalContent,'addStudent') ###(
198    def addStudent(self,dict):
199        students_folder = self.portal_url.getPortalObject().campus.students
200        sid = self.waeup_tool.generateStudentId('?')
201        students_folder.invokeFactory('Student', sid)
202        student_obj = getattr(students_folder,sid)
203        password = self.generatePassword()
204        self.makeStudentMember(sid,password)
205        f2t = self.student_field2types
206        #from pdb import set_trace; set_trace()
207        d = {}
208        d['jamb_sex']  = 'M'
209        if dict.get('sex'):
210            d['jamb_sex']  = 'F'
211        for pt in f2t.keys():
212            student_obj.invokeFactory(pt,f2t[pt]['id'])
213            sub_obj = getattr(student_obj,f2t[pt]['id'])
214            sub_doc = sub_obj.getContent()
215            self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
216            d['Title'] = f2t[pt]['title']
217            for field in f2t[pt]['fields']:
218                d[field] = dict.get(field,'')
219            sub_doc.edit(mapping = d)
220            new_state = f2t[pt]['wf_transition']
221            if new_state != "remain":
222                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
223        entry_session = dict.get('entry_session')
224        wfaction = 'return'
225        if entry_session == self.getSessionId():
226            wfaction = 'admit'
227        self.portal_workflow.doActionFor(student_obj,wfaction)
228        student_obj.manage_setLocalRoles(sid, ['Owner',])
229        return sid,password
230    ###)
231
232    security.declarePublic('getCertificateBrain') ###(
233    def getCertificateBrain(self,cert_id):
234        "do it"
235        res = ZCatalog.searchResults(self.portal_catalog,
236                                {'portal_type':"Certificate",
237                                      'id': cert_id})
238        if res:
239            return res[0]
240        return None
241    ###)
242
243    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
244    def get_csv_filenames(self):
245        "do it"
246        files = [file for file in os.listdir("%s/import/" % (i_home))
247                 if file.endswith('.csv') and file.find('imported') == -1]
248        return files
249    ###)
250
251    security.declarePublic('findStudentByMatricelNo') ###(
252    def findStudentByMatricelNo(self,matric_no):
253        "do it"
254        res = ZCatalog.searchResults(self.portal_catalog,
255                                {'portal_type':"StudentClearance",
256                                 'SearchableText': matric_no})
257        if res:
258            return res[0]
259        return None
260    ###)
261
262    security.declarePublic('makeStudentMember') ###(
263    def makeStudentMember(self,sid,password='uNsEt'):
264        """make the student a member"""
265        membership = self.portal_membership
266        membership.addMember(sid,
267                             password ,
268                             roles=('Member',
269                                     'Student',
270                                     ),
271                             domains='',
272                             properties = {'memberareaCreationFlag': False,
273                                           'homeless': True},)
274        member = membership.getMemberById(sid)
275        self.portal_registration.afterAdd(member, sid, password, None)
276        #self.manage_setLocalRoles(sid, ['Owner',])
277    ###)
278
279    security.declarePublic('makeStudentData') ###(
280    def makeStudentData(self,student_id,email=None,phone_nr=None):
281        "create Datastructure for a returning Student"
282        #import pdb;pdb.set_trace()
283        logger = logging.getLogger('WAeUPTool.makeStudentData')
284        students_folder = self.portal_url.getPortalObject().campus.students
285        #res = self.students_catalog(id=student_id)
286        #if res:
287        #    st = res[0]
288        #res = self.returning_import(matric_no = st.matric_no)
289        res = self.returning_import(id = student_id)
290        if res:
291            student = res[0]
292        else:
293            logger.info('Id %s not found in returning_import' % student_id)
294            return
295        logger.info('%s creates data structure' % student_id)
296        s_results = self.results_import(matric_no = student.matric_no)
297        if s_results:
298            lnr = self.getLevelFromResultsCosCode(s_results)
299            level = "%d00" % lnr
300            verdict,eligible = self.getVerdict(s_results[0].Verdict)
301            if eligible:
302                level = "%d00" % (lnr + 1)
303        else:
304            logger.info('matric_no %s not found in results_import' % student.matric_no)
305            level = 0
306            verdict = 'N/A'
307        #student should not be allowed to perform this transition
308        #wftool = self.portal_workflow
309        #wftool.doActionFor(student,'return')
310        certcode_org = student.Coursemajorcode
311        certcode = makeCertificateCode(certcode_org)
312        certificate_brain = self.getCertificateBrain(certcode)
313        if not certificate_brain:
314            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
315            logger.info(em)
316        matric_no = student.matric_no
317        sid = student_id
318        student_obj = getattr(students_folder,sid)
319        student_obj.invokeFactory('StudentApplication','application')
320        application = student_obj.application
321        self.portal_workflow.doActionFor(application,'open',dest_container=application)
322        da = {'Title': 'Application Data'}
323        student_obj.invokeFactory('StudentPersonal','personal')
324        da['jamb_reg_no'] = student.Entryregno
325        em = self.getEntryMode(student.Entryregno)
326##        em = student.Mode_of_Entry
327##        if em in ('DIRECT', 'DIRECT ENTRY',):
328##            em = 'DE'
329##        elif em in ('U.M.E', 'UNE',):
330##            em = 'UME'
331##        elif not em:
332##            em = "unknown"
333        da['entry_mode'] = em
334        personal = student_obj.personal
335        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
336        dp = {'Title': 'Personal Data'}
337        student_obj.invokeFactory('StudentClearance','clearance')
338        clearance = student_obj.clearance
339        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
340        dc = {'Title': 'Clearance/Eligibility Record'}
341        dc['matric_no'] = matric_no
342        state = student.State
343        lga = student.LGA
344        if state and lga:
345            lga =  state + ' / ' + lga
346        else:
347            lga = "None"
348        da['jamb_lga'] = dc['lga'] = lga
349        da['app_email'] = dp['email'] = email
350        da['app_mobile'] = dp['phone'] = phone_nr
351        dp['firstname'] = student.Firstname
352        dp['middlename'] = student.Middlename
353        dp['lastname'] = student.Lastname
354        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
355        da['jamb_sex'] = student.Sex
356        dp['sex'] = student.Sex == 'F'
357        dp['perm_address'] = student.Permanent_Address
358        application.getContent().edit(mapping=da)
359        self.portal_workflow.doActionFor(application,'close',dest_container=application)
360        personal.getContent().edit(mapping=dp)
361        clearance.getContent().edit(mapping=dc)
362        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
363##        catd = {}
364##        catd['id'] = sid
365##        catd['entry_mode']= da['entry_mode']
366##        catd['matric_no'] = matric_no
367##        catd['jamb_reg_no'] = da['jamb_reg_no']
368##        catd['name'] = "%(firstname)s %(middlename)s %(lastname)s" % dp
369##        catd['sex'] = dp['sex']
370##        catd['level'] = level
371##        catd['verdict'] = verdict
372##        if certificate_brain:
373##            cpath = certificate_brain.getPath().split('/')
374##            catd['faculty'] = cpath[-4]
375##            catd['department'] = cpath[-3]
376##            catd['course'] = certcode
377##        self.students_catalog.modifyRecord(**catd)
378        #
379        # Study Course
380        #
381        student_obj.invokeFactory('StudentStudyCourse','study_course')
382        studycourse = student_obj.study_course
383        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
384        dsc = {}
385        dsc['study_course'] = certcode
386        dsc['current_level'] = level
387        dsc['current_verdict'] = verdict
388        dsc['current_session'] = '06'
389        studycourse.getContent().edit(mapping=dsc)
390        #
391        # Level
392        #
393##        l = getattr(studycourse,level,None)
394##        if l is None:
395##            studycourse.invokeFactory('StudentStudyLevel', level)
396##            l = getattr(studycourse, level)
397##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
398##            l.getContent().edit(mapping={'Title': "Level %s" % level})
399###)
400
401    security.declarePublic('makeStudentLevel') ###(
402    def makeStudentLevel(self,student_id):
403        "create the StudyLevel for a returning Student"
404        #import pdb;pdb.set_trace()
405        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
406        students_folder = self.portal_url.getPortalObject().campus.students
407        res = self.students_catalog(id=student_id)
408        if res:
409            st = res[0]
410        course = st.course
411        matric_no = st.matric_no
412        level = st.level
413        res = self.results_import(matric_no = matric_no)
414        if res:
415            results = res
416        logger.info('%s creating Level %s' % (student_id,level))
417        #
418        # Level
419        #
420        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
421        studycourse = getattr(student_obj,"study_course",None)
422        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
423        l = getattr(studycourse,level,None)
424        if l is None:
425            studycourse.invokeFactory('StudentStudyLevel', level)
426            l = getattr(studycourse, level)
427            self.portal_workflow.doActionFor(l,'open',dest_container=l)
428            l.getContent().edit(mapping={'Title': "Level %s" % level})
429        ###)
430
431    security.declarePublic('getAccommodationInfo') ###(
432    def getAccommodationInfo(self,bed):
433        """return Accommodation Info"""
434        info = {}
435        hall,block,room,letter = bed.split('_')
436        res = ZCatalog.searchResults(self.portal_catalog,portal_type="AccoHall",id=hall)
437        if res and len(res) == 1:
438            hall_brain = res[0]
439            hall_doc = hall_brain.getObject().getContent()
440        else:
441            return info
442        info['hall_title'] = hall_brain.Title
443        info['maintenance_code'] = hall_doc.maintenance_code
444        res = ZCatalog.searchResults(self.portal_catalog,portal_type="ScratchCardBatch")
445        batch_doc = None
446        for brain in res:
447            if brain.id.startswith(info['maintenance_code']):
448                batch_doc = brain.getObject().getContent()
449                break
450        if batch_doc is None:
451            info['maintenance_fee'] = None
452        else:
453            info['maintenance_fee'] = batch_doc.cost
454        return info
455    ###)
456
457    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
458    def deleteAllCourses(self,department="All"):
459        ''' delete the courses'''
460        pm = self.portal_membership
461        member = pm.getAuthenticatedMember()
462
463        if str(member) not in ("henrik","joachim"):
464            return "not possible"
465        if department == "All":
466            res = self.portal_catalog({'meta_type': 'Department'})
467        if len(res) < 1:
468            return "No Departments found"
469
470        deleted = []
471        for dep in res:
472            cf = dep.getObject().courses
473            if cf:
474                cf.manage_delObjects(ids=cf.objectIds())
475                deleted.append("deleted Courses in %s" % dep.getId)
476        return "\r".join(deleted)
477    ###)
478
479    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
480    def getLogfileLines(self,filename="event.log",numlines=20):
481        """Get last NUMLINES lines of logfile FILENAME.
482
483        Return last lines' of a file in the instances logfile directory as
484        a list. The number of returned lines equals `numlines' or less. If
485        less than `numlines' lines are available, the whole file ist
486        returned. If the file can not be opened or some other error
487        occurs, empty list is returend.
488        """
489        result = []
490        lines_hit = 0
491
492        # We only handle files in instances' log directory...
493        logpath = os.path.join(i_home, "log")
494        filename = str(os.path.abspath( os.path.join( logpath, filename )))
495        if not filename.startswith( logpath ):
496            # Attempt to access file outside log-dir...
497            return []
498
499        try:
500            fd = file( filename, "rb" )
501        except IOError:
502            return []
503        if not fd:
504            return []
505
506        if os.linesep == None:
507            linesep = '\n'
508        else:
509            linesep = os.linesep
510
511        # Try to find 'numlines' times a lineseparator, searching from end
512        # and moving to the beginning of file...
513        fd.seek( 0, 2) # Move to end of file...
514        while lines_hit < numlines:
515            if fd.read(1) == linesep[-1]: # This moves filedescriptor
516                                          # one step forward...
517                lines_hit += 1
518            try:
519                fd.seek( -2, 1) # Go two bytes back from current pos...
520            except IOError:
521                # We cannot go back two bytes. Maybe the file is too small...
522                break
523        fd.seek(2,1)
524
525        # Read all lines from current position...
526        result = fd.readlines()
527        # Remove line endings...
528        result = [x.strip() for x in result]
529        fd.close()
530        return result
531    ###)
532
533    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
534    def getCallbacksFromLog(self,filename):
535        """fix Online Payment Transactions from Z2.log entries"""
536        import transaction
537        import random
538        from cgi import parse_qs
539        from urlparse import urlparse
540        #from pdb import set_trace
541        wftool = self.portal_workflow
542        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
543        students_folder = self.portal_url.getPortalObject().campus.students
544        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
545        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
546        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
547        data = re.compile(s)
548        start = True
549        tr_count = 1
550        total = 0
551        #name = 'pume_results'
552        #name = 'epaymentsuccessful_z2log2'
553        name = filename
554        no_import = []
555        imported = []
556        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
557        try:
558            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
559        except:
560            logger.error('Error reading %s' % name)
561            return
562        tas = []
563        for line in transactions:
564            dict = {}
565            items = data.search(line)
566            dict['idict'] = idict = items.groupdict()
567            #print idict
568            #from pdb import set_trace;set_trace()
569            urlparsed = urlparse(idict['get'][4:])
570            #print urlparsed
571            path = urlparsed[2].split('/')
572            dict['student_id'] = student_id = path[8]
573            dict['payment_id'] = payment_id = path[10]
574            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
575            tas.append(dict)
576            tr_count += 1
577        return tas
578    ###)
579
580    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
581    def importOnlinePaymentTransactions(self):
582        """load Online Payment Transactions from CSV values"""
583        import transaction
584        import random
585        #from pdb import set_trace
586        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
587        opt = self.online_payments_import
588        students_folder = self.portal_url.getPortalObject().campus.students
589        start = True
590        tr_count = 1
591        total = 0
592        #name = 'pume_results'
593        name = 'OnlineTransactions'
594        no_import = []
595        imported = []
596        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
597        try:
598            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
599        except:
600            logger.error('Error reading %s.csv' % name)
601            return
602        for pay_transaction in transactions:
603            if start:
604                start = False
605                logger.info('Start loading from %s.csv' % name)
606                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
607                no_import.append('%s,"Error"' % s)
608                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
609                format_error = format + ',"%(Error)s"'
610            data = {}
611
612            # format of the first file sent by Tayo
613            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
614            #data['student_id'] = student_id = pay_transaction['Payer ID']
615            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
616            #data['response_code'] = response_code = pay_transaction['Resp Code']
617            #data['amount'] = amount = pay_transaction['Amount']
618
619            # format of the second file sent by Tayo
620            #data['datetime'] = date = 0
621            #data['student_id'] = student_id = pay_transaction['Payer ID']
622            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
623            #data['response_code'] = response_code = '00'
624            #data['amount'] = amount = pay_transaction['Amount']
625
626            # format of the third file sent by Kehinde
627            data['datetime'] = date = 0
628            data['student_id'] = student_id = pay_transaction['customer_id']
629            data['order_id'] = order_id = pay_transaction['merchant_reference']
630            data['response_code'] = response_code = '00'
631            data['amount'] = amount = pay_transaction['Amount']
632
633            dup = False
634            if response_code == "12":
635                continue
636            try:
637                opt.addRecord(**data)
638            except ValueError:
639                dup = True
640            #from pdb import set_trace;set_trace()
641            if dup:
642                if response_code == "00":
643                    try:
644                        opt.modifyRecord(**data)
645                    except:
646                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
647                        continue
648                else:
649                    pay_transaction['Error'] = "Duplicate order_id"
650                    no_import.append( format_error % pay_transaction)
651                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
652                    continue
653            tr_count += 1
654            if tr_count > 1000:
655                if len(no_import) > 0:
656                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
657                             '\n'.join(no_import) + '\n')
658                    no_import = []
659                em = '%d transactions committed\n' % (tr_count)
660                transaction.commit()
661                regs = []
662                logger.info(em)
663                total += tr_count
664                tr_count = 0
665        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
666                                                '\n'.join(no_import))
667        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
668    ###)
669
670
671    # all workflow transitions refer to students in state returning
672    student_field2types = {   ###(
673                      'StudentApplication':
674                          {'id': 'application',
675                           'title': 'Application Data',
676                           'wf_transition': 'close',
677                           'fields':
678                             ('jamb_reg_no',
679                              'entry_mode',
680                              'entry_session',
681                              'jamb_score',
682                              'app_email',
683                              )
684                              },
685                      #'StudentPume':
686                      #    {'id': 'pume',
687                      #     'title': 'Pume Data',
688                      #     'wf_transition': 'close',
689                      #     'fields':
690                      #       ('pume_score',
691                      #        )
692                      #        },
693                      'StudentClearance':
694                          {'id': 'clearance',
695                           'title': 'Clearance Data',
696                           'wf_transition': 'close',
697                           'fields':
698                             ('matric_no',
699                              'nationality',
700                              'lga',
701                              'birthday',
702                              )
703                              },
704                         'StudentPersonal':
705                          {'id': 'personal',
706                           'title': 'Personal Data',
707                           'wf_transition': 'open',
708                           'fields':
709                             ('firstname',
710                              'middlename',
711                              'lastname',
712                              'sex',
713                              'email',
714                              'phone',
715                              'perm_address',
716                              )
717                              },
718                         'StudentStudyCourse':
719                          {'id': 'study_course',
720                           'title': 'Study Course',
721                           'wf_transition': 'open',
722                           'fields':
723                             ('study_course',
724                              'current_level',
725                              'current_session',
726                              'current_mode',
727                              'current_verdict',
728                              )
729                              },
730                         'PaymentsFolder':
731                          {'id': 'payments',
732                           'title': 'Payments',
733                           'wf_transition': 'open',
734                           'fields':
735                             ()
736                              },
737                         }
738    ###)
739
740
741    security.declareProtected(ModifyPortalContent,'importStudent') ###(
742    def importStudent(self,dict):
743        "create a students record due import"
744        logger = logging.getLogger('WAeUPTool.importStudent')
745        students_folder = self.portal_url.getPortalObject().campus.students
746        jamb_reg_no = dict.get('jamb_reg_no',None)
747        if jamb_reg_no:
748            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
749            if res:
750                return '',"jamb_reg_no exists"
751        matric_no = dict.get('matric_no',None)
752        if matric_no:
753            res = self.students_catalog(matric_no = matric_no)
754            if res:
755                return '',"matric_no exists"
756        sid = self.waeup_tool.generateStudentId('?')
757        students_folder.invokeFactory('Student', sid)
758        student_obj = getattr(students_folder,sid)
759        f2t = self.student_field2types
760        d = {}
761        d['jamb_sex']  = 'M'
762        if dict.get('sex'):
763            d['jamb_sex']  = 'F'
764        for pt in f2t.keys():
765            student_obj.invokeFactory(pt,f2t[pt]['id'])
766            sub_obj = getattr(student_obj,f2t[pt]['id'])
767            sub_doc = sub_obj.getContent()
768            d['Title'] = f2t[pt]['title']
769            for field in f2t[pt]['fields']:
770                d[field] = dict.get(field,'')
771            sub_doc.edit(mapping = d)
772            new_state = f2t[pt]['wf_transition']
773            if new_state != "remain":
774                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
775        wfaction = 'return'
776        self.portal_workflow.doActionFor(student_obj,wfaction)
777        student_obj.manage_setLocalRoles(sid, ['Owner',])
778        return sid,''
779    ###)
780
781    security.declareProtected(ModifyPortalContent,'importEditStudent') ###(
782    def importEditStudent(self,dict):
783        "edit a students record due import"
784        logger = logging.getLogger('WAeUPTool.importEditStudent')
785        students_folder = self.portal_url.getPortalObject().campus.students
786        sid = dict.get('id',None)
787        jamb_reg_no = dict.get('jamb_reg_no',None)
788        matric_no = dict.get('matric_no',None)
789        if sid:
790            res = self.students_catalog(id = sid)
791            if not res:
792                return '',"no student with id %s" % sid
793            elif matric_no and res[0].matric_no and\
794              matric_no != res[0].matric_no:
795                return '%s' % res[0].id ,"student has no matric_no %s" % matric_no
796            elif jamb_reg_no and res[0].jamb_reg_no and\
797              jamb_reg_no != res[0].jamb_reg_no:
798                return '%s' % res[0].id ,"student has no jamb_reg_no %s" % jamb_reg_no
799        elif matric_no:
800            res = self.students_catalog(matric_no = matric_no)
801            if not res:
802                return '',"no student with matric_no %s" % matric_no
803            elif jamb_reg_no and res[0].jamb_reg_no and\
804              jamb_reg_no != res[0].jamb_reg_no:
805                return '%s' % res[0].id ,"student has no jamb_reg_no %s" % jamb_reg_no
806        elif jamb_reg_no:
807            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
808            if not res:
809                return '',"no student with jamb_reg_no %s" % jamb_reg_no
810        sid = res[0].id
811        student_obj = getattr(students_folder,sid)
812        f2t = self.student_field2types
813        d = {}
814        d['jamb_sex']  = 'M'
815        if dict.get('sex'):
816            d['jamb_sex']  = 'F'
817        for pt in f2t.keys():
818            sub_obj = getattr(student_obj,f2t[pt]['id'],None)
819            if sub_obj is None:
820                try:
821                    student_obj.invokeFactory(pt,f2t[pt]['id'])
822                except:
823                    continue
824                sub_obj = getattr(student_obj,f2t[pt]['id'])
825            sub_doc = sub_obj.getContent()
826            # self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
827            d['Title'] = f2t[pt]['title']
828            for field in f2t[pt]['fields']:
829                d[field] = dict.get(field,'')
830            sub_doc.edit(mapping = d)
831            # new_state = f2t[pt]['wf_transition']
832            # if new_state != "remain":
833            #     self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
834        # wfaction = 'return'
835        # self.portal_workflow.doActionFor(student_obj,wfaction)
836        # student_obj.manage_setLocalRoles(sid, ['Owner',])
837        return sid,''
838    ###)
839
840    security.declareProtected(ModifyPortalContent,"importData")###(
841    def importData(self,filename,name,edit=False):
842        """load data from CSV values"""
843        import transaction
844        import random
845
846        pm = self.portal_membership
847        member = pm.getAuthenticatedMember()
848
849        logger = logging.getLogger('WAeUPTool.importData')
850        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
851        students_folder = self.portal_url.getPortalObject().campus.students
852        start = True
853        tr_count = 1
854        total_imported = 0
855        total_not_imported = 0
856        total = 0
857        iname = "import_%s" % name
858        stool = getToolByName(self, 'portal_schemas')
859        ltool = getToolByName(self, 'portal_layouts')
860        schema = stool._getOb(iname)
861        if schema is None:
862            em = 'No such schema %s' % iname
863            logger.error('No such schema %s' % iname)
864            return em
865        layout = ltool._getOb(iname)
866        if layout is None:
867            em = 'No such layout %s' % iname
868            logger.error(em)
869            return em
870        validators = {}
871        for widget in layout.keys():
872            validators[widget] = layout[widget].validate
873        if edit:
874            importer_name = "importEdit%s" % name.capitalize()
875        else:
876            importer_name = "import%s" % name.capitalize()
877        importer = getattr(self, '%s' % importer_name,None)
878        if importer is None:
879            em = 'No importer function %s' % importer_name
880            logger.error(em)
881            return em
882        not_imported = []
883        imported = []
884        try:
885            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
886        except:
887            em = 'Error reading %s.csv' % filename
888            logger.error(em)
889            return em
890        for item in items:
891            tr_count += 1
892            if start:
893                start = False
894                adapters = [MappingStorageAdapter(schema, item)]
895                dm = DataModel(item, adapters,context=self)
896                logger.info('%s starts import from %s.csv' % (member,filename))
897                import_keys = [k for k in item.keys() if not k.startswith('ignore')]
898                diff2schema = set(import_keys).difference(set(schema.keys()))
899                diff2layout = set(import_keys).difference(set(layout.keys()))
900                if diff2schema:
901                    em = "not ignorable key(s) %s found in heading" % diff2schema
902                    return em
903                s = ','.join(['"%s"' % fn for fn in import_keys])
904                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
905                s = '"id",' + s
906                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
907                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
908                format_error = format + ',"%(Error)s"'
909                format = '"%(id)s",'+ format
910            ds = DataStructure(data=item,datamodel=dm)
911            error_string = ""
912            for k in import_keys:
913                # if k == "birthday":
914                #     from pdb import set_trace; set_trace()
915                if not validators[k](ds):
916                    error_string += " %s : %s" % (k,ds.getError(k))
917            if not error_string:
918                item.update(dm)
919                item['id'],error = importer(item)
920                if error:
921                    error_string += error
922            if error_string:
923                item['Error'] = error_string
924                not_imported.append(format_error % item)
925                total_not_imported += 1
926            else:
927                imported.append(format % item)
928                total_imported += 1
929            total += 1
930            if tr_count > 1000:
931                if len(not_imported) > 0:
932                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
933                             '\n'.join(not_imported) + '\n')
934                    not_imported = []
935                if len(imported) > 0:
936                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
937                             '\n'.join(imported) + '\n')
938                    imported = []
939                em = '%d transactions committed\n' % (tr_count)
940                transaction.commit()
941                regs = []
942                logger.info(em)
943                tr_count = 0
944        if len(imported) > 0:
945            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
946                                                '\n'.join(imported))
947        if len(not_imported) > 0:
948            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
949                                                '\n'.join(not_imported))
950        em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
951        logger.info(em)
952        return em
953    ###)
954
955InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.