source: WAeUP_SRP/trunk/WAeUPTool.py @ 1881

Last change on this file since 1881 was 1875, checked in by joachim, 18 years ago

new import edit

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