Changeset 9960


Ignore:
Timestamp:
16 Feb 2013, 12:20:06 (12 years ago)
Author:
Henrik Bettermann
Message:

Extend StudentStudyCourseProcessor? so that we can transfer students by import.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/students
Files:
3 edited

Legend:

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

    r9735 r9960  
    3131from zope.interface import Interface
    3232from zope.schema import getFields
    33 from zope.component import queryUtility, getUtility
     33from zope.component import queryUtility, getUtility, createObject
    3434from zope.event import notify
    3535from zope.catalog.interfaces import ICatalog
     
    4141from waeup.kofa.interfaces import MessageFactory as _
    4242from waeup.kofa.students.interfaces import (
    43     IStudent, IStudentStudyCourse,
     43    IStudent, IStudentStudyCourse, IStudentStudyCourseTransfer,
    4444    IStudentUpdateByRegNo, IStudentUpdateByMatricNo,
    4545    IStudentStudyLevel, ICourseTicketImport,
     
    408408    name = u'StudentStudyCourse Processor (update only)'
    409409    iface = IStudentStudyCourse
     410    iface_transfer = IStudentStudyCourseTransfer
    410411    factory_name = 'waeup.StudentStudyCourse'
    411412
     
    425426        """Update obj to the values given in row.
    426427        """
     428        entry_mode = row.get('entry_mode', None)
     429        certificate = row.get('certificate', None)
     430        # If students are being transferred a new studycourse is created and
     431        # the old one is moved.
     432        if entry_mode == 'transfer':
     433            studycourse = createObject(u'waeup.StudentStudyCourse')
     434            student = obj.__parent__
     435            studycourse.entry_session = obj.entry_session
     436            if 'studycourse_1' in student.keys():
     437                student['studycourse_2'] = obj
     438            else:
     439                student['studycourse_1'] = obj
     440            del student['studycourse']
     441            student['studycourse'] = studycourse
     442            student.__parent__.logger.info(
     443                '%s - transferred from %s to %s' % (
     444                student.student_id, obj.certificate.code, certificate.code))
     445            history = IObjectHistory(student)
     446            history.addMessage('Transferred from %s to %s' % (
     447                obj.certificate.code, certificate.code))
     448            obj = student['studycourse']
    427449        items_changed = super(StudentStudyCourseProcessor, self).updateEntry(
    428450            obj, row, site, filename)
     
    438460        """Validates all values in row.
    439461        """
    440         errs, inv_errs, conv_dict = super(
    441             StudentStudyCourseProcessor, self).checkConversion(row, mode=mode)
     462        # We have to use the correct interface. Transfer
     463        # updates have different constraints.
     464        entry_mode = row.get('entry_mode', None)
     465        if entry_mode == 'transfer':
     466            converter = IObjectConverter(self.iface_transfer)
     467        else:
     468            converter = IObjectConverter(self.iface)
     469        errs, inv_errs, conv_dict =  converter.fromStringDict(
     470            row, self.factory_name, mode=mode)
     471
    442472        # We have to check if current_level is in range of certificate.
    443473        if 'certificate' in conv_dict and 'current_level' in conv_dict:
     
    454484        problems.
    455485        """
     486        certificate = getattr(obj, 'certificate', None)
     487        entry_session = getattr(obj, 'entry_session', None)
    456488        current_level = row.get('current_level', None)
     489        entry_mode = row.get('entry_mode', None)
     490        # We have to ensure that the student can be transferred.
     491        if entry_mode == 'transfer':
     492            if certificate is None or entry_session is None:
     493                return 'Former study course record incomplete.'
     494            if 'studycourse_1' in obj.__parent__.keys() and \
     495                'studycourse_2' in obj.__parent__.keys():
     496                return 'Maximum number of transfers exceeded.'
    457497        if current_level:
    458498            if current_level == 999 and \
    459499                obj.__parent__.state in FORBIDDEN_POSTGRAD_STATES:
    460500                return 'Not a pg student.'
    461             certificate = getattr(obj, 'certificate', None)
    462501            cert = row.get('certificate', None)
    463502            if certificate is None and cert is None:
    464503                return 'No certificate to check level.'
    465             if certificate is not None and (
     504            if certificate is not None and cert is None and (
    466505                current_level < certificate.start_level or \
    467506                current_level > certificate.end_level+120):
     
    779818    factory_name = 'waeup.StudentStudyCourse'
    780819
    781     additional_fields = [
    782         'current_session',
    783         'current_level',
    784         'bypass_validation',
    785         'validated_by']
    786 
    787820    def checkUpdateRequirements(self, obj, row, site):
    788821        """Checks requirements the studycourse and the student must fulfill
  • main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py

    r9949 r9960  
    460460        )
    461461
     462    entry_mode = schema.Choice(
     463        title = _(u'Entry Mode'),
     464        source = StudyModeSource(),
     465        required = False,
     466        readonly = False,
     467        )
     468
     469    entry_session = schema.Choice(
     470        title = _(u'Entry Session'),
     471        source = academic_sessions_vocab,
     472        #default = datetime.now().year,
     473        required = False,
     474        readonly = False,
     475        )
     476
    462477
    463478IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py

    r9919 r9960  
    2727from time import time
    2828from zope.event import notify
    29 from zope.component import createObject
     29from zope.component import createObject, queryUtility
    3030from zope.component.hooks import setSite, clearSite
     31from zope.catalog.interfaces import ICatalog
    3132from zope.interface.verify import verifyClass, verifyObject
    3233from hurry.workflow.interfaces import IWorkflowState
     
    8889
    8990STUDYCOURSE_HEADER_FIELDS = STUDYCOURSE_SAMPLE_DATA.split(
     91    '\n')[0].split(',')
     92
     93TRANSFER_SAMPLE_DATA = open(
     94    os.path.join(os.path.dirname(__file__), 'sample_transfer_data.csv'),
     95    'rb').read()
     96
     97TRANSFER_HEADER_FIELDS = TRANSFER_SAMPLE_DATA.split(
    9098    '\n')[0].split(',')
    9199
     
    571579            self.workdir, 'sample_studycourse_data.csv')
    572580        open(self.csv_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
     581        self.csv_file_transfer = os.path.join(
     582            self.workdir, 'sample_transfer_data.csv')
     583        open(self.csv_file_transfer, 'wb').write(TRANSFER_SAMPLE_DATA)
    573584        return
    574585
     
    639650            dict(reg_number='1', current_level=100), self.app)
    640651        self.assertEqual(err, 'No certificate to check level.')
     652        # When transferring students the method also checks
     653        # if the former studycourse is complete.
     654        err = self.processor.checkUpdateRequirements(
     655            self.student['studycourse'],
     656            dict(reg_number='1', certificate='CERT1', current_level=200,
     657            entry_mode='transfer'), self.app)
     658        self.assertEqual(err, 'Former study course record incomplete.')
     659        self.student['studycourse'].certificate = self.certificate
     660        self.student['studycourse'].entry_session = 2005
     661        # The method doesn't care if current_level
     662        # is not in range of CERT1. This is done by checkConversion
     663        # if certificate is in row.
     664        err = self.processor.checkUpdateRequirements(
     665            self.student['studycourse'],
     666            dict(reg_number='1', certificate='CERT1', current_level=200,
     667            entry_mode='transfer'), self.app)
     668        self.assertTrue(err is None)
    641669
    642670    def test_import(self):
     
    649677        self.assertEqual(studycourse.certificate.code, u'CERT1')
    650678        shutil.rmtree(os.path.dirname(fin_file))
     679
     680    def test_import_transfer(self):
     681        self.certificate2 = createObject('waeup.Certificate')
     682        self.certificate2.code = 'CERT2'
     683        self.certificate2.application_category = 'basic'
     684        self.certificate2.start_level = 200
     685        self.certificate2.end_level = 500
     686        self.certificate2.study_mode = u'ug_pt'
     687        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
     688            self.certificate2)
     689        num, num_warns, fin_file, fail_file = self.processor.doImport(
     690            self.csv_file_transfer, TRANSFER_HEADER_FIELDS,'update')
     691        self.assertEqual(num_warns,0)
     692        self.assertEqual(self.student['studycourse'].certificate.code, 'CERT2')
     693        self.assertEqual(self.student['studycourse_1'].certificate.code, 'CERT1')
     694        self.assertEqual(self.student['studycourse'].entry_mode, 'transfer')
     695        self.assertEqual(self.student['studycourse_1'].entry_mode, 'ug_ft')
     696        self.assertEqual(self.student.current_mode, 'ug_pt')
     697        shutil.rmtree(os.path.dirname(fin_file))
     698        # Transer has bee logged.
     699        logcontent = open(self.logfile).read()
     700        self.assertTrue(
     701            'INFO - system - K1000000 - transferred from CERT1 to CERT2\n'
     702            in logcontent)
     703        self.assertTrue(
     704            'INFO - system - '
     705            'StudentStudyCourse Processor (update only) - '
     706            'sample_transfer_data - K1000000 - updated: entry_mode=transfer, '
     707            'certificate=CERT2, current_session=2009, current_level=300'
     708            in logcontent)
     709        # A history message has been added.
     710        history = ' '.join(self.student.history.messages)
     711        self.assertTrue(
     712            "Transferred from CERT1 to CERT2 by system" in history)
     713        # The catalog has been updated
     714        cat = queryUtility(ICatalog, name='students_catalog')
     715        results = list(
     716            cat.searchResults(
     717            certcode=('CERT2', 'CERT2')))
     718        self.assertTrue(results[0] is self.student)
     719        results = list(
     720            cat.searchResults(
     721            current_session=(2009, 2009)))
     722        self.assertTrue(results[0] is self.student)
     723        results = list(
     724            cat.searchResults(
     725            certcode=('CERT1', 'CERT1')))
     726        self.assertEqual(len(results), 0)
    651727
    652728class StudentStudyLevelProcessorTest(StudentImportExportSetup):
Note: See TracChangeset for help on using the changeset viewer.