Index: /main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/tests/test_batching.py
===================================================================
--- /main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/tests/test_batching.py	(revision 15141)
+++ /main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/tests/test_batching.py	(revision 15142)
@@ -665,4 +665,28 @@
             entry_mode='transfer'), self.app)
         self.assertTrue(err is None)
+        # In state 'transcript validated' studycourses are locked.
+        IWorkflowState(self.student).setState('transcript validated')
+        err = self.processor.checkUpdateRequirements(
+            self.student['studycourse'],
+            dict(reg_number='1', current_level=999), self.app)
+        self.assertEqual(err, 'Studycourse is locked.')
+        # In state 'graduated' studycourses are also locked.
+        IWorkflowState(self.student).setState('graduated')
+        err = self.processor.checkUpdateRequirements(
+            self.student['studycourse'],
+            dict(reg_number='1', current_level=999), self.app)
+        self.assertEqual(err, 'Studycourse is locked.')
+        # In state 'transcript released' studycourses are also locked ...
+        IWorkflowState(self.student).setState('transcript released')
+        err = self.processor.checkUpdateRequirements(
+            self.student['studycourse'],
+            dict(reg_number='1', current_level=999), self.app)
+        self.assertEqual(err, 'Studycourse is locked.')
+        # ... but not in state 'transcript requested'.
+        IWorkflowState(self.student).setState('transcript requested')
+        err = self.processor.checkUpdateRequirements(
+            self.student['studycourse'],
+            dict(reg_number='1', current_level=999), self.app)
+        self.assertTrue(err is None)
 
     def test_import(self):
@@ -826,4 +850,28 @@
         shutil.rmtree(os.path.dirname(fin_file))
 
+    def test_import_update_locked(self):
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file, STUDYLEVEL_HEADER_FIELDS,'create')
+        shutil.rmtree(os.path.dirname(fin_file))
+        # In state 'transcript validated' studylevels can't be edited
+        student = self.app['students']['X666666']
+        IWorkflowState(student).setState('transcript validated')
+        # Two more records could't be imported because course tickets
+        # of X666666 are locked
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file, STUDYLEVEL_HEADER_FIELDS,'update')
+        self.assertEqual(num_warns,5)
+        content = open(fail_file).read()
+        self.assertEqual(
+            content,
+            'reg_number,level_verdict,level_session,matric_number,level,--ERRORS--\r\n'
+            '1,<IGNORE>,2008,<IGNORE>,100,Studylevel is locked.\r\n'
+            '1,<IGNORE>,2008,<IGNORE>,200,Studylevel is locked.\r\n'
+            '1,A,2008,<IGNORE>,111,level: Invalid value\r\n'
+            '1,A,2008,<IGNORE>,nonsense,level: Invalid value\r\n'
+            '1,A,2008,<IGNORE>,<IGNORE>,Cannot update: no such entry\r\n'
+            )
+        shutil.rmtree(os.path.dirname(fin_file))
+
     def test_import_remove(self):
         # We perform the same import twice,
@@ -989,4 +1037,28 @@
             'INFO - system - K1000000 - Course ticket in 100 removed: COURSE1'
             in logcontent)
+
+    def test_import_update_locked(self):
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file, COURSETICKET_HEADER_FIELDS,'create')
+        shutil.rmtree(os.path.dirname(fin_file))
+        # In state 'transcript validated' course tickets can't edited
+        student = self.app['students']['X666666']
+        IWorkflowState(student).setState('transcript validated')
+        num, num_warns, fin_file, fail_file = self.processor.doImport(
+            self.csv_file, COURSETICKET_HEADER_FIELDS,'update')
+        fail_file = open(fail_file).read()
+        # Two more records could't be imported because course tickets
+        # of X666666 are locked
+        self.assertEqual(num_warns,7)
+        self.assertEqual(fail_file,
+            'reg_number,code,mandatory,level,level_session,score,matric_number,--ERRORS--\r\n'
+            '1,COURSE1,True,100,<IGNORE>,1,<IGNORE>,Studycourse is locked.\r\n'
+            '1,COURSE1,True,200,2008,1,<IGNORE>,Studycourse is locked.\r\n'
+            '1,COURSE1,<IGNORE>,nonsense,<IGNORE>,5,<IGNORE>,Cannot update: no such entry\r\n'
+            '1,NONSENSE,<IGNORE>,100,<IGNORE>,5,<IGNORE>,code: non-existent\r\n'
+            '1,COURSE1,<IGNORE>,200,2004,6,<IGNORE>,level_session: does not match 2008\r\n'
+            '1,COURSE1,<IGNORE>,300,2008,6,<IGNORE>,level object: does not exist\r\n'
+            '1,COURSE1,<IGNORE>,300,2008X,6,<IGNORE>,level_session: Invalid value\r\n')
+        shutil.rmtree(os.path.dirname(fin_file))
 
 class PaymentProcessorTest(StudentImportExportSetup):
