Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py	(revision 9940)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py	(revision 9960)
@@ -27,6 +27,7 @@
 from time import time
 from zope.event import notify
-from zope.component import createObject
+from zope.component import createObject, queryUtility
 from zope.component.hooks import setSite, clearSite
+from zope.catalog.interfaces import ICatalog
 from zope.interface.verify import verifyClass, verifyObject
 from hurry.workflow.interfaces import IWorkflowState
@@ -88,4 +89,11 @@
 
 STUDYCOURSE_HEADER_FIELDS = STUDYCOURSE_SAMPLE_DATA.split(
+    '\n')[0].split(',')
+
+TRANSFER_SAMPLE_DATA = open(
+    os.path.join(os.path.dirname(__file__), 'sample_transfer_data.csv'),
+    'rb').read()
+
+TRANSFER_HEADER_FIELDS = TRANSFER_SAMPLE_DATA.split(
     '\n')[0].split(',')
 
@@ -571,4 +579,7 @@
             self.workdir, 'sample_studycourse_data.csv')
         open(self.csv_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
+        self.csv_file_transfer = os.path.join(
+            self.workdir, 'sample_transfer_data.csv')
+        open(self.csv_file_transfer, 'wb').write(TRANSFER_SAMPLE_DATA)
         return
 
@@ -639,4 +650,21 @@
             dict(reg_number='1', current_level=100), self.app)
         self.assertEqual(err, 'No certificate to check level.')
+        # When transferring students the method also checks
+        # if the former studycourse is complete.
+        err = self.processor.checkUpdateRequirements(
+            self.student['studycourse'],
+            dict(reg_number='1', certificate='CERT1', current_level=200,
+            entry_mode='transfer'), self.app)
+        self.assertEqual(err, 'Former study course record incomplete.')
+        self.student['studycourse'].certificate = self.certificate
+        self.student['studycourse'].entry_session = 2005
+        # The method doesn't care if current_level
+        # is not in range of CERT1. This is done by checkConversion
+        # if certificate is in row.
+        err = self.processor.checkUpdateRequirements(
+            self.student['studycourse'],
+            dict(reg_number='1', certificate='CERT1', current_level=200,
+            entry_mode='transfer'), self.app)
+        self.assertTrue(err is None)
 
     def test_import(self):
@@ -649,4 +677,52 @@
         self.assertEqual(studycourse.certificate.code, u'CERT1')
         shutil.rmtree(os.path.dirname(fin_file))
+
+    def test_import_transfer(self):
+        self.certificate2 = createObject('waeup.Certificate')
+        self.certificate2.code = 'CERT2'
+        self.certificate2.application_category = 'basic'
+        self.certificate2.start_level = 200
+        self.certificate2.end_level = 500
+        self.certificate2.study_mode = u'ug_pt'
+        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
+            self.certificate2)
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file_transfer, TRANSFER_HEADER_FIELDS,'update')
+        self.assertEqual(num_warns,0)
+        self.assertEqual(self.student['studycourse'].certificate.code, 'CERT2')
+        self.assertEqual(self.student['studycourse_1'].certificate.code, 'CERT1')
+        self.assertEqual(self.student['studycourse'].entry_mode, 'transfer')
+        self.assertEqual(self.student['studycourse_1'].entry_mode, 'ug_ft')
+        self.assertEqual(self.student.current_mode, 'ug_pt')
+        shutil.rmtree(os.path.dirname(fin_file))
+        # Transer has bee logged.
+        logcontent = open(self.logfile).read()
+        self.assertTrue(
+            'INFO - system - K1000000 - transferred from CERT1 to CERT2\n'
+            in logcontent)
+        self.assertTrue(
+            'INFO - system - '
+            'StudentStudyCourse Processor (update only) - '
+            'sample_transfer_data - K1000000 - updated: entry_mode=transfer, '
+            'certificate=CERT2, current_session=2009, current_level=300'
+            in logcontent)
+        # A history message has been added.
+        history = ' '.join(self.student.history.messages)
+        self.assertTrue(
+            "Transferred from CERT1 to CERT2 by system" in history)
+        # The catalog has been updated
+        cat = queryUtility(ICatalog, name='students_catalog')
+        results = list(
+            cat.searchResults(
+            certcode=('CERT2', 'CERT2')))
+        self.assertTrue(results[0] is self.student)
+        results = list(
+            cat.searchResults(
+            current_session=(2009, 2009)))
+        self.assertTrue(results[0] is self.student)
+        results = list(
+            cat.searchResults(
+            certcode=('CERT1', 'CERT1')))
+        self.assertEqual(len(results), 0)
 
 class StudentStudyLevelProcessorTest(StudentImportExportSetup):
