source: WAeUP_SRP/trunk/WAeUPTool.py @ 1849

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

fix

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