source: WAeUP_SRP/trunk/WAeUPTool.py @ 1869

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

temporary changes only to import 6 admitted students (ticket #246)

These changes show, which settings must be changed for the import of admitted students. We should be able to switch between different student import states.

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