Ignore:
Timestamp:
22 Mar 2012, 07:21:20 (13 years ago)
Author:
Henrik Bettermann
Message:

Add verdict processor.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/students
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py

    r7933 r7951  
    3131from zope.event import notify
    3232from zope.catalog.interfaces import ICatalog
    33 from hurry.workflow.interfaces import IWorkflowState
     33from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
    3434from waeup.kofa.interfaces import (
    3535    IBatchProcessor, FatalCSVError, IObjectConverter, IUserAccount,
    36     IObjectHistory)
     36    IObjectHistory, VALIDATED)
    3737from waeup.kofa.students.interfaces import (
    3838    IStudent, IStudentStudyCourse,
    3939    IStudentUpdateByRegNo, IStudentUpdateByMatricNo,
    4040    IStudentStudyLevel, ICourseTicket,
    41     IStudentOnlinePayment)
     41    IStudentOnlinePayment, IStudentVerdictUpdate)
    4242from waeup.kofa.students.workflow import  IMPORTABLE_STATES
    4343from waeup.kofa.utils.batching import BatchProcessor
     
    639639                return errs, inv_errs, conv_dict
    640640        return errs, inv_errs, conv_dict
     641
     642class StudentVerdictProcessor(StudentStudyCourseProcessor):
     643    """A batch processor for verdicts.
     644
     645    Import verdicts and perform workflow transitions.
     646    """
     647
     648    util_name = 'verdictupdater'
     649    grok.name(util_name)
     650
     651    name = u'Verdict Processor (update only)'
     652    iface = IStudentVerdictUpdate
     653    factory_name = 'waeup.StudentStudyCourse'
     654
     655    @property
     656    def available_fields(self):
     657        return sorted(list(set(
     658            ['student_id','reg_number','matric_number',
     659                'current_session', 'current_level'] + getFields(
     660                self.iface).keys())))
     661
     662    def checkUpdateRequirements(self, obj, row, site):
     663        """Checks requirements the studycourse and the student must fulfill
     664        before being updated.
     665        """
     666        # Check if current_levels correspond
     667        if obj.current_level != row['current_level']:
     668            return 'Current level does not correspond.'
     669        # Check if current_sessions correspond
     670        if obj.current_session != row['current_session']:
     671            return 'Current session does not correspond.'
     672        # Check if student is in state REGISTERED
     673        if obj.getStudent().state != VALIDATED:
     674            return 'Student in wrong state.'
     675        return None
     676
     677    def updateEntry(self, obj, row, site):
     678        """Update obj to the values given in row.
     679        """
     680        items_changed = ''
     681        for key, value in row.items():
     682            # Skip fields not declared in interface plus
     683            # current_verdict and current_level
     684            if hasattr(obj, key) and not key in [
     685                'current_verdict','current_level']:
     686                setattr(obj, key, value)
     687            items_changed += '%s=%s, ' % (key,value)
     688        parent = self.getParent(row, site)
     689        parent.__parent__.logger.info(
     690            '%s - Verdict updated: %s'
     691            % (parent.student_id, items_changed))
     692        # Fire transition
     693        IWorkflowInfo(obj.__parent__).fireTransition('return')
     694        # Update the students_catalog
     695        notify(grok.ObjectModifiedEvent(obj.__parent__))
     696        return
     697
     698    def checkConversion(self, row, mode='ignore'):
     699        """Validates all values in row.
     700        """
     701        converter = IObjectConverter(self.iface)
     702        errs, inv_errs, conv_dict =  converter.fromStringDict(
     703            row, self.factory_name)
     704        return errs, inv_errs, conv_dict
  • main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py

    r7915 r7951  
    334334        )
    335335
     336class IStudentVerdictUpdate(IKofaObject):
     337    """A interface for verdict imports.
     338
     339    """
     340
     341    current_verdict = schema.Choice(
     342        title = _(u'Current Verdict'),
     343        source = VerdictSource(),
     344        required = True,
     345        )
     346
     347    current_session = schema.Choice(
     348        title = _(u'Current Session'),
     349        source = academic_sessions_vocab,
     350        default = None,
     351        required = True,
     352        )
     353
     354    current_level = schema.Choice(
     355        title = _(u'Current Level'),
     356        source = StudyLevelSource(),
     357        default = None,
     358        required = True,
     359        )
     360
    336361class IStudentStudyLevel(IKofaObject):
    337362    """A container for course tickets.
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_student_data.csv

    r7643 r7951  
    1 student_id,firstname,lastname,reg_number,date_of_birth,matric_number,email,phone
    2 X666666,Aaren,Pieri,1,1990-01-02,100000,aa@aa.ng,1234
    3 ,Aaren,Finau,2,1990-01-03,100001,aa@aa.ng,1234
    4 ,Aaren,Berson,3,1990-01-04,100002,aa@aa.ng,1234
     1student_id,firstname,lastname,reg_number,date_of_birth,matric_number,email,phone,reg_state
     2X666666,Aaren,Pieri,1,1990-01-02,100000,aa@aa.ng,1234,courses validated
     3,Aaren,Finau,2,1990-01-03,100001,aa@aa.ng,1234,courses validated
     4,Aaren,Berson,3,1990-01-04,100002,aa@aa.ng,1234,courses validated
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py

    r7947 r7951  
    3434    StudentProcessor, StudentStudyCourseProcessor,
    3535    StudentStudyLevelProcessor, CourseTicketProcessor,
    36     StudentOnlinePaymentProcessor)
     36    StudentOnlinePaymentProcessor, StudentVerdictProcessor)
    3737from waeup.kofa.students.student import Student
    3838from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
     
    6565
    6666STUDYCOURSE_HEADER_FIELDS = STUDYCOURSE_SAMPLE_DATA.split(
     67    '\n')[0].split(',')
     68
     69VERDICT_SAMPLE_DATA = open(
     70    os.path.join(os.path.dirname(__file__), 'sample_verdict_data.csv'),
     71    'rb').read()
     72
     73VERDICT_HEADER_FIELDS = VERDICT_SAMPLE_DATA.split(
    6774    '\n')[0].split(',')
    6875
     
    108115        self.app = self.getRootFolder()['app']
    109116        setSite(app)
    110 
    111         # Import students with subobjects
    112         #student_file = os.path.join(self.workdir, 'sample_student_data.csv')
    113         #open(student_file, 'wb').write(STUDENT_SAMPLE_DATA)
    114         #num, num_warns, fin_file, fail_file = StudentProcessor().doImport(
    115         #    student_file, STUDENT_HEADER_FIELDS)
    116         #shutil.rmtree(os.path.dirname(fin_file))
    117117
    118118        # Populate university
     
    126126        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    127127            self.certificate)
    128 
    129         self.importer = StudentStudyCourseProcessor()
    130         self.csv_file = os.path.join(
    131             self.workdir, 'sample_studycourse_data.csv')
    132         open(self.csv_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
    133128        return
    134129
     
    297292
    298293
    299 class StudentStudyCourseProcessorTest(FunctionalTestCase):
    300 
    301     layer = FunctionalLayer
     294class StudentStudyCourseProcessorTest(StudentImportExportSetup):
    302295
    303296    def setUp(self):
    304297        super(StudentStudyCourseProcessorTest, self).setUp()
    305         self.dc_root = tempfile.mkdtemp()
    306         self.workdir = tempfile.mkdtemp()
    307         app = University()
    308         app['datacenter'].setStoragePath(self.dc_root)
    309         self.getRootFolder()['app'] = app
    310         self.app = self.getRootFolder()['app']
    311         setSite(app)
    312298
    313299        # Import students with subobjects
     
    318304        shutil.rmtree(os.path.dirname(fin_file))
    319305
    320         # Populate university
    321         self.certificate = createObject('waeup.Certificate')
    322         self.certificate.code = 'CERT1'
    323         self.certificate.application_category = 'basic'
    324         self.certificate.start_level = 200
    325         self.certificate.end_level = 500
    326         self.app['faculties']['fac1'] = Faculty()
    327         self.app['faculties']['fac1']['dep1'] = Department()
    328         self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    329             self.certificate)
    330 
    331306        self.processor = StudentStudyCourseProcessor()
    332307        self.csv_file = os.path.join(
     
    335310        return
    336311
    337     def tearDown(self):
    338         super(StudentStudyCourseProcessorTest, self).tearDown()
    339         shutil.rmtree(self.workdir)
    340         shutil.rmtree(self.dc_root)
    341         clearSite()
    342         return
    343 
    344312    def test_interface(self):
    345313        # Make sure we fulfill the interface contracts.
     
    384352        shutil.rmtree(os.path.dirname(fin_file))
    385353
    386 class StudentStudyLevelProcessorTest(FunctionalTestCase):
    387 
    388     layer = FunctionalLayer
     354class StudentVerdictProcessorTest(StudentImportExportSetup):
     355
    389356
    390357    def setUp(self):
    391         super(StudentStudyLevelProcessorTest, self).setUp()
    392         self.dc_root = tempfile.mkdtemp()
    393         self.workdir = tempfile.mkdtemp()
    394         app = University()
    395         app['datacenter'].setStoragePath(self.dc_root)
    396         self.getRootFolder()['app'] = app
    397         self.app = self.getRootFolder()['app']
    398         setSite(app)
     358        super(StudentVerdictProcessorTest, self).setUp()
    399359
    400360        # Import students with subobjects
     
    404364            student_file, STUDENT_HEADER_FIELDS)
    405365        shutil.rmtree(os.path.dirname(fin_file))
    406 
    407         # Populate university
    408         self.certificate = createObject('waeup.Certificate')
    409         self.certificate.code = 'CERT1'
    410         self.certificate.application_category = 'basic'
    411         self.certificate.start_level = 200
    412         self.certificate.end_level = 500
    413         self.app['faculties']['fac1'] = Faculty()
    414         self.app['faculties']['fac1']['dep1'] = Department()
    415         self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    416             self.certificate)
    417366
    418367        # Update study courses
     
    425374        shutil.rmtree(os.path.dirname(fin_file))
    426375
     376        self.processor = StudentVerdictProcessor()
     377        self.csv_file = os.path.join(
     378            self.workdir, 'sample_verdict_data.csv')
     379        open(self.csv_file, 'wb').write(VERDICT_SAMPLE_DATA)
     380        return
     381
     382    def test_import(self):
     383        num, num_warns, fin_file, fail_file = self.processor.doImport(
     384            self.csv_file, VERDICT_HEADER_FIELDS,'update')
     385        self.assertEqual(num_warns,0)
     386        studycourse = self.processor.getEntry(dict(reg_number='1'), self.app)
     387        self.assertEqual(studycourse.certificate.code, u'CERT1')
     388        shutil.rmtree(os.path.dirname(fin_file))
     389
     390
     391class StudentStudyLevelProcessorTest(StudentImportExportSetup):
     392
     393    def setUp(self):
     394        super(StudentStudyLevelProcessorTest, self).setUp()
     395
     396        # Import students with subobjects
     397        student_file = os.path.join(self.workdir, 'sample_student_data.csv')
     398        open(student_file, 'wb').write(STUDENT_SAMPLE_DATA)
     399        num, num_warns, fin_file, fail_file = StudentProcessor().doImport(
     400            student_file, STUDENT_HEADER_FIELDS)
     401        shutil.rmtree(os.path.dirname(fin_file))
     402
     403        # Update study courses
     404        studycourse_file = os.path.join(
     405            self.workdir, 'sample_studycourse_data.csv')
     406        open(studycourse_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
     407        processor = StudentStudyCourseProcessor()
     408        num, num_warns, fin_file, fail_file = processor.doImport(
     409            studycourse_file, STUDYCOURSE_HEADER_FIELDS,'update')
     410        shutil.rmtree(os.path.dirname(fin_file))
     411
    427412        self.processor = StudentStudyLevelProcessor()
    428413        self.csv_file = os.path.join(
    429414            self.workdir, 'sample_studylevel_data.csv')
    430415        open(self.csv_file, 'wb').write(STUDYLEVEL_SAMPLE_DATA)
    431 
    432     def tearDown(self):
    433         super(StudentStudyLevelProcessorTest, self).tearDown()
    434         shutil.rmtree(self.workdir)
    435         shutil.rmtree(self.dc_root)
    436         clearSite()
    437         return
    438416
    439417    def test_interface(self):
     
    471449       
    472450
    473 class CourseTicketProcessorTest(FunctionalTestCase):
    474 
    475     layer = FunctionalLayer
     451class CourseTicketProcessorTest(StudentImportExportSetup):
    476452
    477453    def setUp(self):
    478454        super(CourseTicketProcessorTest, self).setUp()
    479         self.dc_root = tempfile.mkdtemp()
    480         self.workdir = tempfile.mkdtemp()
    481         app = University()
    482         app['datacenter'].setStoragePath(self.dc_root)
    483         self.getRootFolder()['app'] = app
    484         self.app = self.getRootFolder()['app']
    485         setSite(app)
    486455
    487456        # Import students with subobjects
     
    492461        shutil.rmtree(os.path.dirname(fin_file))
    493462
    494         # Populate university
    495         self.certificate = createObject('waeup.Certificate')
    496         self.certificate.code = 'CERT1'
    497         self.certificate.application_category = 'basic'
    498         self.certificate.start_level = 200
    499         self.certificate.end_level = 500
    500         self.app['faculties']['fac1'] = Faculty()
    501         self.app['faculties']['fac1']['dep1'] = Department()
    502         self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    503             self.certificate)
     463        # Add course and course referrer
    504464        self.course = createObject('waeup.Course')
    505465        self.course.code = 'COURSE1'
     
    534494            self.workdir, 'sample_courseticket_data.csv')
    535495        open(self.csv_file, 'wb').write(COURSETICKET_SAMPLE_DATA)
    536 
    537     def tearDown(self):
    538         super(CourseTicketProcessorTest, self).tearDown()
    539         shutil.rmtree(self.workdir)
    540         shutil.rmtree(self.dc_root)
    541         clearSite()
    542         return
    543496
    544497    def test_interface(self):
     
    579532        shutil.rmtree(os.path.dirname(fin_file))
    580533
    581 class PaymentProcessorTest(FunctionalTestCase):
    582 
    583     layer = FunctionalLayer
     534class PaymentProcessorTest(StudentImportExportSetup):
    584535
    585536    def setUp(self):
    586537        super(PaymentProcessorTest, self).setUp()
    587         self.dc_root = tempfile.mkdtemp()
    588         self.workdir = tempfile.mkdtemp()
    589         app = University()
    590         app['datacenter'].setStoragePath(self.dc_root)
    591         self.getRootFolder()['app'] = app
    592         self.app = self.getRootFolder()['app']
    593         setSite(app)
    594538
    595539        # Add student with payment
     
    616560            self.workdir, 'sample_payment_data.csv')
    617561        open(self.csv_file, 'wb').write(PAYMENT_SAMPLE_DATA)
    618 
    619     def tearDown(self):
    620         super(PaymentProcessorTest, self).tearDown()
    621         shutil.rmtree(self.workdir)
    622         shutil.rmtree(self.dc_root)
    623         clearSite()
    624         return
    625562
    626563    def test_interface(self):
     
    690627        StudentProcessorTest,StudentStudyCourseProcessorTest,
    691628        StudentStudyLevelProcessorTest,CourseTicketProcessorTest,
    692         PaymentProcessorTest,]:
     629        PaymentProcessorTest,StudentVerdictProcessorTest]:
    693630        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
    694631                testcase
Note: See TracChangeset for help on using the changeset viewer.