source: WAeUP_SRP/trunk/WAeUPTool.py @ 1864

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

fix

  • Property svn:keywords set to Id
File size: 39.1 KB
RevLine 
[197]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 $
[1174]20"""The WAeUP Tool Box.
[197]21"""
22
23from AccessControl import ClassSecurityInfo
[828]24from Acquisition import aq_inner
25from Acquisition import aq_parent
26from Globals import DTMLFile
27from Globals import InitializeClass
28from OFS.SimpleItem import SimpleItem
[197]29
[1747]30from Products.CPSSchemas.DataStructure import DataStructure
31from Products.CPSSchemas.DataModel import DataModel
32from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
[828]33from Products.CMFCore.ActionProviderBase import ActionProviderBase
34from Products.CMFCore.permissions import View
35from Products.ZCatalog.ZCatalog import ZCatalog
36from Products.CMFCore.permissions import ModifyPortalContent
[197]37from Products.CMFCore.utils import UniqueObject
[1194]38from Products.CMFCore.URLTool import URLTool
[1747]39from Products.CMFCore.utils import getToolByName
[1151]40from Students import makeCertificateCode
[1285]41from Globals import package_home,INSTANCE_HOME
42p_home = package_home(globals())
43i_home = INSTANCE_HOME
[1620]44import DateTime
45import logging
[1170]46import transaction
[1620]47import csv,re,os
[1707]48from Products.AdvancedQuery import Eq, Between, Le,In
[197]49
[1707]50def getObject(object,name):
51    if object.hasObject(name):
52        return getattr(object,name)
53    return None
[1720]54
[828]55class WAeUPTool(UniqueObject, SimpleItem, ActionProviderBase):
[197]56    """WAeUP tool"""
57
[828]58    id = 'waeup_tool'
[197]59    meta_type = 'WAeUP Tool'
[828]60    _actions = ()
[197]61
62    security = ClassSecurityInfo()
[828]63    security.declareObjectProtected(View)
[197]64
[828]65    manage_options = ( ActionProviderBase.manage_options
66                     + SimpleItem.manage_options
67                     )
68
[1818]69    def rwrite(self,s): ###(
[1707]70        response = self.REQUEST.RESPONSE
71        response.setHeader('Content-type','text/html; charset=ISO-8859-15')
72        response.write("%s<br />\r\n" % s)
[1818]73    ###)
[1174]74
[1818]75    def sleep(self,secs): ###(
76        "sleep"
77        import time
78        time.sleep(secs)
79        return
[1827]80
[1818]81###)
82
83    security.declareProtected(ModifyPortalContent,'openLog') ###(
[1716]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
[1818]94###)
95
96    security.declareProtected(ModifyPortalContent,'writeLog') ###(
[1716]97    def writeLog(self,logfile,s):
98        """write to the log file"""
99        logfile.write(s)
100
[1818]101###)
[1720]102
[1151]103    def generateStudentId(self,letter): ###(
104        import random
105        r = random
[1194]106        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
107        if letter == '?':
[1151]108            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
109        sid = "%c%d" % (letter,r.randint(99999,1000000))
[1720]110        students = self.portal_url.getPortalObject().campus.students
[1721]111##        while hasattr(students, sid):
112##            sid = "%c%d" % (letter,r.randint(99999,1000000))
113        while self.students_catalog(id = sid):
[1720]114            sid = "%c%d" % (letter,r.randint(99999,1000000))
[1151]115        return sid
[1460]116    ###)
[1415]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
[1151]128    ###)
[828]129
[1261]130    security.declareProtected(ModifyPortalContent,'getCredential') ###(
[1250]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
[1263]136        return getattr(student_entry,"password","not set")
[1261]137    ###)
[1250]138
[1460]139    security.declarePublic('checkPassword') ###(
[1467]140    def checkPassword(self,student_id,password):
[1460]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
[1467]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:
[1571]153            return
[1467]154        setattr(student_entry,'password',password)
155    ###)
156
[1647]157    security.declareProtected(View,'doCommit') ###(
[1401]158    def doCommit(self,logger=None):
159        "commit some transactions"
160        transaction.commit()
161    ###)
162
[1285]163    security.declarePublic('loadStudentFoto') ###(
[1813]164    def loadStudentFoto(self,student,filename,folder):
[1285]165        "return a student passport picture"
166        app_doc = student.application.getContent()
[1813]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)
[1285]172        #import pdb;pdb.set_trace()
[1286]173        if os.path.exists(picture1):
174            file = open(picture1)
175        elif os.path.exists(picture2):
[1287]176            file = open(picture2)
[1286]177        else:
[1287]178            return "passport picture not found %s" % picture1
[1286]179
[1285]180        outfile = file.read()
181        app_doc.manage_addFile('passport',
182                               file=outfile,
[1818]183                               title="%s.jpg" % filename)
[1286]184        return "successfully loaded passport picture"
[1285]185    ###)
186
[1170]187    security.declareProtected(ModifyPortalContent,'createOne') ###(
[1194]188    def createOne(self,students_folder,student_brain,letter,commit=False):
189        sid = self.waeup_tool.generateStudentId(letter)
[1170]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
[1752]209    security.declareProtected(ModifyPortalContent,'addStudent') ###(
210    def addStudent(self,dict):
[1415]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)
[1728]217        f2t = self.student_field2types
[1772]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'
[1728]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)
[1772]228            d['Title'] = f2t[pt]['title']
[1728]229            for field in f2t[pt]['fields']:
[1749]230                d[field] = dict.get(field,'')
[1728]231            sub_doc.edit(mapping = d)
[1781]232            new_state = f2t[pt]['wf_transition']
[1772]233            if new_state != "remain":
234                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
[1728]235        entry_session = dict.get('entry_session')
[1415]236        wfaction = 'return'
[1728]237        if entry_session == self.getSessionId():
[1415]238            wfaction = 'admit'
239        self.portal_workflow.doActionFor(student_obj,wfaction)
240        student_obj.manage_setLocalRoles(sid, ['Owner',])
241        return sid,password
242    ###)
243
[1151]244    security.declarePublic('getCertificateBrain') ###(
245    def getCertificateBrain(self,cert_id):
246        "do it"
[1849]247        res = ZCatalog.searchResults(self.portal_catalog_real,
[1151]248                                {'portal_type':"Certificate",
249                                      'id': cert_id})
250        if res:
251            return res[0]
252        return None
253    ###)
[1160]254
[1756]255    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
256    def get_csv_filenames(self):
257        "do it"
[1759]258        files = [file for file in os.listdir("%s/import/" % (i_home))
[1756]259                 if file.endswith('.csv') and file.find('imported') == -1]
260        return files
261    ###)
262
[1151]263    security.declarePublic('findStudentByMatricelNo') ###(
264    def findStudentByMatricelNo(self,matric_no):
265        "do it"
[1849]266        res = ZCatalog.searchResults(self.portal_catalog_real,
[1151]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)
[1261]288        #self.manage_setLocalRoles(sid, ['Owner',])
[1151]289    ###)
[1160]290
[1151]291    security.declarePublic('makeStudentData') ###(
[1158]292    def makeStudentData(self,student_id,email=None,phone_nr=None):
[1151]293        "create Datastructure for a returning Student"
[1406]294        #import pdb;pdb.set_trace()
[1571]295        logger = logging.getLogger('WAeUPTool.makeStudentData')
[1151]296        students_folder = self.portal_url.getPortalObject().campus.students
[1794]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)
[1798]301        res = self.returning_import(id = student_id)
[1151]302        if res:
[1160]303            student = res[0]
[1794]304        else:
[1816]305            logger.info('Id %s not found in returning_import' % student_id)
[1794]306            return
[1580]307        logger.info('%s creates data structure' % student_id)
[1794]308        s_results = self.results_import(matric_no = student.matric_no)
[1816]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'
[1171]319        #student should not be allowed to perform this transition
[1174]320        #wftool = self.portal_workflow
321        #wftool.doActionFor(student,'return')
[1151]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
[1169]333        self.portal_workflow.doActionFor(application,'open',dest_container=application)
[1151]334        da = {'Title': 'Application Data'}
335        student_obj.invokeFactory('StudentPersonal','personal')
336        da['jamb_reg_no'] = student.Entryregno
[1462]337        em = self.getEntryMode(student.Entryregno)
[1460]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"
[1401]345        da['entry_mode'] = em
[1151]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
[1169]351        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
[1151]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"
[1174]360        da['jamb_lga'] = dc['lga'] = lga
[1173]361        da['app_email'] = dp['email'] = email
362        da['app_mobile'] = dp['phone'] = phone_nr
[1411]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)
[1174]367        da['jamb_sex'] = student.Sex
[1151]368        dp['sex'] = student.Sex == 'F'
369        dp['perm_address'] = student.Permanent_Address
370        application.getContent().edit(mapping=da)
[1169]371        self.portal_workflow.doActionFor(application,'close',dest_container=application)
[1151]372        personal.getContent().edit(mapping=dp)
373        clearance.getContent().edit(mapping=dc)
[1169]374        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
[1759]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)
[1151]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
[1401]398        dsc['current_level'] = level
399        dsc['current_verdict'] = verdict
[1827]400        dsc['current_mode'] = em
[1759]401        dsc['current_session'] = '06'
[1151]402        studycourse.getContent().edit(mapping=dsc)
403        #
404        # Level
405        #
[1198]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})
[1194]412###)
[1160]413
[1194]414    security.declarePublic('makeStudentLevel') ###(
415    def makeStudentLevel(self,student_id):
416        "create the StudyLevel for a returning Student"
417        #import pdb;pdb.set_trace()
[1571]418        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
[1194]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
[1571]429        logger.info('%s creating Level %s' % (student_id,level))
[1194]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
[1151]444    security.declarePublic('getAccommodationInfo') ###(
[828]445    def getAccommodationInfo(self,bed):
446        """return Accommodation Info"""
447        info = {}
448        hall,block,room,letter = bed.split('_')
[1846]449        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
[828]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
[1846]457        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
[828]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
[1151]468    ###)
[828]469
[1151]470    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
471    def deleteAllCourses(self,department="All"):
472        ''' delete the courses'''
473        pm = self.portal_membership
474        member = pm.getAuthenticatedMember()
[1160]475
[1151]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"
[1160]482
[1151]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)
[1160]490    ###)
[1151]491
[1572]492    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
493    def getLogfileLines(self,filename="event.log",numlines=20):
494        """Get last NUMLINES lines of logfile FILENAME.
[1160]495
[1572]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
[1700]546    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
[1665]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
[1620]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")
[1625]600        opt = self.online_payments_import
[1620]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 = {}
[1644]624
[1781]625            # format of the first file sent by Tayo
[1643]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']
[1644]631
[1781]632            # format of the second file sent by Tayo
[1798]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']
[1813]638
[1798]639            # format of the third file sent by Kehinde
[1643]640            data['datetime'] = date = 0
[1798]641            data['student_id'] = student_id = pay_transaction['customer_id']
642            data['order_id'] = order_id = pay_transaction['merchant_reference']
[1644]643            data['response_code'] = response_code = '00'
[1813]644            data['amount'] = amount = pay_transaction['Amount']
[1644]645
[1620]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":
[1798]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
[1620]661                else:
[1674]662                    pay_transaction['Error'] = "Duplicate order_id"
[1620]663                    no_import.append( format_error % pay_transaction)
[1674]664                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
[1620]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 = []
[1645]672                em = '%d transactions committed\n' % (tr_count)
[1620]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
[1786]683
[1781]684    # all workflow transitions refer to students in state returning
[1756]685    student_field2types = {   ###(
686                      'StudentApplication':
687                          {'id': 'application',
688                           'title': 'Application Data',
[1781]689                           'wf_transition': 'close',
[1756]690                           'fields':
691                             ('jamb_reg_no',
692                              'entry_mode',
693                              'entry_session',
694                              'jamb_score',
[1786]695                              'app_email',
[1756]696                              )
697                              },
[1786]698                      #'StudentPume':
699                      #    {'id': 'pume',
700                      #     'title': 'Pume Data',
701                      #     'wf_transition': 'close',
702                      #     'fields':
703                      #       ('pume_score',
704                      #        )
705                      #        },
[1756]706                      'StudentClearance':
707                          {'id': 'clearance',
708                           'title': 'Clearance Data',
[1781]709                           'wf_transition': 'close',
[1756]710                           'fields':
711                             ('matric_no',
712                              'nationality',
713                              'lga',
[1804]714                              'birthday',
[1756]715                              )
716                              },
717                         'StudentPersonal':
718                          {'id': 'personal',
719                           'title': 'Personal Data',
[1781]720                           'wf_transition': 'open',
[1756]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',
[1781]734                           'wf_transition': 'open',
[1756]735                           'fields':
736                             ('study_course',
737                              'current_level',
738                              'current_session',
739                              'current_mode',
740                              'current_verdict',
741                              )
742                              },
[1775]743                         'PaymentsFolder':
744                          {'id': 'payments',
745                           'title': 'Payments',
[1781]746                           'wf_transition': 'open',
[1775]747                           'fields':
748                             ()
749                              },
[1756]750                         }
751    ###)
752
753
[1772]754    security.declareProtected(ModifyPortalContent,'importStudent') ###(
[1818]755    def importStudent(self,mapping):
[1781]756        "create a students record due import"
757        logger = logging.getLogger('WAeUPTool.importStudent')
[1747]758        students_folder = self.portal_url.getPortalObject().campus.students
[1818]759        jamb_reg_no = mapping.get('jamb_reg_no',None)
[1747]760        if jamb_reg_no:
761            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
762            if res:
[1749]763                return '',"jamb_reg_no exists"
[1818]764        matric_no = mapping.get('matric_no',None)
[1747]765        if matric_no:
766            res = self.students_catalog(matric_no = matric_no)
767            if res:
[1749]768                return '',"matric_no exists"
[1747]769        sid = self.waeup_tool.generateStudentId('?')
770        students_folder.invokeFactory('Student', sid)
771        student_obj = getattr(students_folder,sid)
772        f2t = self.student_field2types
[1772]773        d = {}
774        d['jamb_sex']  = 'M'
[1818]775        if mapping.get('sex'):
[1772]776            d['jamb_sex']  = 'F'
[1747]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()
[1772]781            d['Title'] = f2t[pt]['title']
[1747]782            for field in f2t[pt]['fields']:
[1818]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]
[1747]789            sub_doc.edit(mapping = d)
[1781]790            new_state = f2t[pt]['wf_transition']
[1758]791            if new_state != "remain":
792                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
[1752]793        wfaction = 'return'
794        self.portal_workflow.doActionFor(student_obj,wfaction)
[1747]795        student_obj.manage_setLocalRoles(sid, ['Owner',])
796        return sid,''
797    ###)
798
[1774]799    security.declareProtected(ModifyPortalContent,'importEditStudent') ###(
[1818]800    def importEditStudent(self,mapping):
[1781]801        "edit a students record due import"
802        logger = logging.getLogger('WAeUPTool.importEditStudent')
[1774]803        students_folder = self.portal_url.getPortalObject().campus.students
[1818]804        sid = mapping.get('id',None)
805        jamb_reg_no = mapping.get('jamb_reg_no',None)
806        matric_no = mapping.get('matric_no',None)
[1774]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
[1844]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
[1774]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
[1844]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
[1774]829        sid = res[0].id
830        student_obj = getattr(students_folder,sid)
831        f2t = self.student_field2types
832        d = {}
833        d['jamb_sex']  = 'M'
[1818]834        if mapping.get('sex'):
[1774]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:
[1786]839                try:
840                    student_obj.invokeFactory(pt,f2t[pt]['id'])
841                except:
842                    continue
[1774]843                sub_obj = getattr(student_obj,f2t[pt]['id'])
844            sub_doc = sub_obj.getContent()
[1781]845            # self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
[1774]846            d['Title'] = f2t[pt]['title']
847            for field in f2t[pt]['fields']:
[1844]848                if not mapping.get(field,None):
849                    continue
[1818]850                d[field] = mapping.get(field,'')
[1774]851            sub_doc.edit(mapping = d)
[1781]852            # new_state = f2t[pt]['wf_transition']
[1774]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
[1730]861    security.declareProtected(ModifyPortalContent,"importData")###(
[1774]862    def importData(self,filename,name,edit=False):
[1730]863        """load data from CSV values"""
864        import transaction
865        import random
[1775]866
[1773]867        pm = self.portal_membership
[1775]868        member = pm.getAuthenticatedMember()
869
[1747]870        logger = logging.getLogger('WAeUPTool.importData')
[1730]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
[1756]875        total_imported = 0
876        total_not_imported = 0
[1730]877        total = 0
[1749]878        iname = "import_%s" % name
[1747]879        stool = getToolByName(self, 'portal_schemas')
880        ltool = getToolByName(self, 'portal_layouts')
881        schema = stool._getOb(iname)
[1730]882        if schema is None:
[1772]883            em = 'No such schema %s' % iname
884            logger.error('No such schema %s' % iname)
[1756]885            return em
[1747]886        layout = ltool._getOb(iname)
[1730]887        if layout is None:
[1772]888            em = 'No such layout %s' % iname
[1756]889            logger.error(em)
890            return em
[1730]891        validators = {}
892        for widget in layout.keys():
[1749]893            validators[widget] = layout[widget].validate
[1774]894        if edit:
895            importer_name = "importEdit%s" % name.capitalize()
896        else:
897            importer_name = "import%s" % name.capitalize()
[1772]898        importer = getattr(self, '%s' % importer_name,None)
899        if importer is None:
900            em = 'No importer function %s' % importer_name
[1756]901            logger.error(em)
902            return em
[1747]903        not_imported = []
[1730]904        imported = []
905        try:
[1747]906            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
[1730]907        except:
[1756]908            em = 'Error reading %s.csv' % filename
909            logger.error(em)
910            return em
[1730]911        for item in items:
912            tr_count += 1
913            if start:
914                start = False
[1747]915                adapters = [MappingStorageAdapter(schema, item)]
916                dm = DataModel(item, adapters,context=self)
[1773]917                logger.info('%s starts import from %s.csv' % (member,filename))
[1804]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
[1753]924                s = ','.join(['"%s"' % fn for fn in import_keys])
[1772]925                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
926                s = '"id",' + s
[1756]927                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
[1730]928                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
929                format_error = format + ',"%(Error)s"'
[1756]930                format = '"%(id)s",'+ format
[1747]931            ds = DataStructure(data=item,datamodel=dm)
932            error_string = ""
[1730]933            for k in import_keys:
[1747]934                if not validators[k](ds):
935                    error_string += " %s : %s" % (k,ds.getError(k))
936            if not error_string:
[1756]937                item.update(dm)
[1772]938                item['id'],error = importer(item)
[1747]939                if error:
940                    error_string += error
941            if error_string:
942                item['Error'] = error_string
943                not_imported.append(format_error % item)
[1756]944                total_not_imported += 1
[1747]945            else:
[1821]946                em = format % item
947                imported.append(em)
948                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
[1756]949                total_imported += 1
950            total += 1
[1730]951            if tr_count > 1000:
[1747]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(
[1772]958                             '\n'.join(imported) + '\n')
[1747]959                    imported = []
[1730]960                em = '%d transactions committed\n' % (tr_count)
961                transaction.commit()
962                regs = []
963                logger.info(em)
964                tr_count = 0
[1756]965        if len(imported) > 0:
[1747]966            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
967                                                '\n'.join(imported))
[1756]968        if len(not_imported) > 0:
[1747]969            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
970                                                '\n'.join(not_imported))
[1759]971        em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
[1756]972        logger.info(em)
973        return em
[1730]974    ###)
975
[828]976InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.