source: WAeUP_SRP/trunk/WAeUPTool.py @ 1838

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

ticket #230

  • Property svn:keywords set to Id
File size: 39.0 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 1827 2007-05-29 08:11:16Z 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
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,
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,
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,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,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 matric_no:
818            res = self.students_catalog(matric_no = matric_no)
819            if not res:
820                return '',"no student with matric_no %s" % matric_no
821            elif jamb_reg_no and res[0].jamb_reg_no and\
822              jamb_reg_no != res[0].jamb_reg_no:
823                return '%s' % res[0].id ,"student has no jamb_reg_no %s" % jamb_reg_no
824        elif jamb_reg_no:
825            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
826            if not res:
827                return '',"no student with jamb_reg_no %s" % jamb_reg_no
828        sid = res[0].id
829        student_obj = getattr(students_folder,sid)
830        f2t = self.student_field2types
831        d = {}
832        d['jamb_sex']  = 'M'
833        if mapping.get('sex'):
834            d['jamb_sex']  = 'F'
835        for pt in f2t.keys():
836            sub_obj = getattr(student_obj,f2t[pt]['id'],None)
837            if sub_obj is None:
838                try:
839                    student_obj.invokeFactory(pt,f2t[pt]['id'])
840                except:
841                    continue
842                sub_obj = getattr(student_obj,f2t[pt]['id'])
843            sub_doc = sub_obj.getContent()
844            # self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
845            d['Title'] = f2t[pt]['title']
846            for field in f2t[pt]['fields']:
847                d[field] = mapping.get(field,'')
848            sub_doc.edit(mapping = d)
849            # new_state = f2t[pt]['wf_transition']
850            # if new_state != "remain":
851            #     self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
852        # wfaction = 'return'
853        # self.portal_workflow.doActionFor(student_obj,wfaction)
854        # student_obj.manage_setLocalRoles(sid, ['Owner',])
855        return sid,''
856    ###)
857
858    security.declareProtected(ModifyPortalContent,"importData")###(
859    def importData(self,filename,name,edit=False):
860        """load data from CSV values"""
861        import transaction
862        import random
863
864        pm = self.portal_membership
865        member = pm.getAuthenticatedMember()
866
867        logger = logging.getLogger('WAeUPTool.importData')
868        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
869        students_folder = self.portal_url.getPortalObject().campus.students
870        start = True
871        tr_count = 1
872        total_imported = 0
873        total_not_imported = 0
874        total = 0
875        iname = "import_%s" % name
876        stool = getToolByName(self, 'portal_schemas')
877        ltool = getToolByName(self, 'portal_layouts')
878        schema = stool._getOb(iname)
879        if schema is None:
880            em = 'No such schema %s' % iname
881            logger.error('No such schema %s' % iname)
882            return em
883        layout = ltool._getOb(iname)
884        if layout is None:
885            em = 'No such layout %s' % iname
886            logger.error(em)
887            return em
888        validators = {}
889        for widget in layout.keys():
890            validators[widget] = layout[widget].validate
891        if edit:
892            importer_name = "importEdit%s" % name.capitalize()
893        else:
894            importer_name = "import%s" % name.capitalize()
895        importer = getattr(self, '%s' % importer_name,None)
896        if importer is None:
897            em = 'No importer function %s' % importer_name
898            logger.error(em)
899            return em
900        not_imported = []
901        imported = []
902        try:
903            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
904        except:
905            em = 'Error reading %s.csv' % filename
906            logger.error(em)
907            return em
908        for item in items:
909            tr_count += 1
910            if start:
911                start = False
912                adapters = [MappingStorageAdapter(schema, item)]
913                dm = DataModel(item, adapters,context=self)
914                logger.info('%s starts import from %s.csv' % (member,filename))
915                import_keys = [k for k in item.keys() if not k.startswith('ignore')]
916                diff2schema = set(import_keys).difference(set(schema.keys()))
917                diff2layout = set(import_keys).difference(set(layout.keys()))
918                if diff2schema:
919                    em = "not ignorable key(s) %s found in heading" % diff2schema
920                    return em
921                s = ','.join(['"%s"' % fn for fn in import_keys])
922                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
923                s = '"id",' + s
924                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
925                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
926                format_error = format + ',"%(Error)s"'
927                format = '"%(id)s",'+ format
928            ds = DataStructure(data=item,datamodel=dm)
929            error_string = ""
930            for k in import_keys:
931                if not validators[k](ds):
932                    error_string += " %s : %s" % (k,ds.getError(k))
933            if not error_string:
934                item.update(dm)
935                item['id'],error = importer(item)
936                if error:
937                    error_string += error
938            if error_string:
939                item['Error'] = error_string
940                not_imported.append(format_error % item)
941                total_not_imported += 1
942            else:
943                em = format % item
944                imported.append(em)
945                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
946                total_imported += 1
947            total += 1
948            if tr_count > 1000:
949                if len(not_imported) > 0:
950                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
951                             '\n'.join(not_imported) + '\n')
952                    not_imported = []
953                if len(imported) > 0:
954                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
955                             '\n'.join(imported) + '\n')
956                    imported = []
957                em = '%d transactions committed\n' % (tr_count)
958                transaction.commit()
959                regs = []
960                logger.info(em)
961                tr_count = 0
962        if len(imported) > 0:
963            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
964                                                '\n'.join(imported))
965        if len(not_imported) > 0:
966            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
967                                                '\n'.join(not_imported))
968        em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
969        logger.info(em)
970        return em
971    ###)
972
973InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.