source: WAeUP_SRP/trunk/WAeUPTool.py @ 1811

Last change on this file since 1811 was 1804, checked in by joachim, 18 years ago

fix for #205, add more widgets for import_data

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