Index: main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/batching.py	(revision 15203)
@@ -649,4 +649,10 @@
     `fcode` and `dcode` can nevermore be changed, neither via the user interface
     nor by import. Other values can be overwritten by import.
+
+    `ticket_session` is an additional attribute which can be used to store the 
+    session of the course when it was taken. Usually this information is 
+    redundantbecause the the parent study level object already contains this 
+    information except for the study level zero container which can be used to
+    store 'orphaned' course tickets.
     """
     grok.implements(IBatchProcessor)
@@ -669,5 +675,5 @@
             'mandatory', 'score', 'carry_over', 'automatic',
             'outstanding', 'course_category', 'level_session',
-            'title', 'credits', 'passmark', 'semester'
+            'title', 'credits', 'passmark', 'semester', 'ticket_session'
             ] + self.additional_fields
         return sorted(fields)
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15203)
@@ -1030,12 +1030,18 @@
         level_code = self.request.form.get('addlevel', None)
         level_session = self.request.form.get('level_session', None)
-        if not level_session:
+        if not level_session and not level_code == '0':
             self.flash(_('You must select a session for the level.'),
                        type="warning")
             self.redirect(self.url(self.context, u'@@manage')+'#tab2')
             return
+        if level_session and level_code == '0':
+            self.flash(_('Level zero must not be assigned a session.'),
+                       type="warning")
+            self.redirect(self.url(self.context, u'@@manage')+'#tab2')
+            return
         studylevel = createObject(u'waeup.StudentStudyLevel')
         studylevel.level = int(level_code)
-        studylevel.level_session = int(level_session)
+        if level_code != '0':
+            studylevel.level_session = int(level_session)
         try:
             self.context.addStudentStudyLevel(
@@ -1306,5 +1312,5 @@
         self.semester_dict = getUtility(IKofaUtils).SEMESTER_DICT
         self.level_dict = level_dict(self.context)
-        self.session_dict = dict(
+        self.session_dict = dict([(None, 'None'),] +
             [(item[1], item[0]) for item in academic_sessions()])
         self.studymode_dict = getUtility(IKofaUtils).STUDY_MODES_DICT
@@ -1340,5 +1346,5 @@
         self.semester_dict = getUtility(IKofaUtils).SEMESTER_DICT
         self.level_dict = level_dict(self.context)
-        self.session_dict = dict(
+        self.session_dict = dict([(None, 'None'),] +
             [(item[1], item[0]) for item in academic_sessions()])
         self.studymode_dict = getUtility(IKofaUtils).STUDY_MODES_DICT
@@ -1483,5 +1489,5 @@
         level_title = translate(self.context.level_title, 'waeup.kofa',
             target_language=lang)
-        return _('${a}: Study Level ${b}', mapping = {
+        return _('${a}: ${b}', mapping = {
             'a':self.context.student.display_fullname,
             'b':level_title})
@@ -1613,5 +1619,5 @@
         level_title = translate(self.context.level_title, 'waeup.kofa',
             target_language=lang)
-        return _('Manage study level ${a}',
+        return _('Manage ${a}',
             mapping = {'a':level_title})
 
@@ -1777,5 +1783,6 @@
     grok.name('index')
     grok.require('waeup.viewStudent')
-    form_fields = grok.AutoFields(ICourseTicket).omit('course_category')
+    form_fields = grok.AutoFields(ICourseTicket).omit('course_category',
+        'ticket_session')
     grok.template('courseticketpage')
     pnav = 4
@@ -1803,4 +1810,5 @@
     form_fields['automatic'].for_display = True
     form_fields['carry_over'].for_display = True
+    form_fields['ticket_session'].for_display = True
     pnav = 4
     grok.template('courseticketmanagepage')
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/transcript.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/transcript.pt	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/transcript.pt	(revision 15203)
@@ -46,5 +46,5 @@
                                       level['tickets_2'], level['tickets_3'])">
       <tr tal:repeat="ticket semester_tickets">
-        <td tal:content="python: view.level_dict[ticket.level]">LEVEL</td>
+        <td tal:content="python: view.level_dict.get('ticket.level', ticket.level)">LEVEL</td>
         <td tal:content="python: view.session_dict[ticket.level_session]">SESSION</td>
         <td tal:content="python: view.semester_dict[ticket.semester]">SEMESTER</td>
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py	(revision 15203)
@@ -18,5 +18,5 @@
 #from datetime import datetime
 from zope.component import getUtility
-from zope.interface import Attribute, Interface
+from zope.interface import Attribute, Interface, invariant, Invalid
 from zope import schema
 from zc.sourcefactory.contextual import BasicContextualSourceFactory
@@ -662,4 +662,10 @@
         )
 
+    ticket_session = schema.Choice(
+        title = _(u'Imported Session'),
+        source = academic_sessions_vocab,
+        required = False,
+        )
+
     passmark = schema.Int(
         title = _(u'Passmark'),
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_courseticket_data.csv
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_courseticket_data.csv	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/sample_courseticket_data.csv	(revision 15203)
@@ -1,10 +1,10 @@
-reg_number,matric_number,level,code,score,mandatory,level_session
-1,,100,COURSE1,1,True,
-2,,100,COURSE1,2,False,
-,100002,100,COURSE1,3,False,
-1,,200,COURSE1,1,True,2008
-1,,nonsense,COURSE1,5,,
-1,,100,NONSENSE,5,,
-1,,200,COURSE1,6,,2004
-1,,300,COURSE1,6,,2008
-1,,300,COURSE1,6,,2008X
+reg_number,matric_number,level,code,score,mandatory,level_session,ticket_session
+1,,100,COURSE1,1,True,,
+2,,100,COURSE1,2,False,,
+,100002,100,COURSE1,3,False,,
+1,,200,COURSE1,1,True,2008,
+1,,nonsense,COURSE1,5,,,
+1,,100,NONSENSE,5,,,
+1,,200,COURSE1,6,,2004,
+1,,300,COURSE1,6,,2008,
+1,,300,COURSE1,6,,2008X,
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 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_batching.py	(revision 15203)
@@ -957,10 +957,10 @@
         self.assertEqual(num_warns,5)
         self.assertEqual(fail_file,
-            'reg_number,code,mandatory,level,level_session,score,matric_number,--ERRORS--\r\n'
-            '1,COURSE1,<IGNORE>,nonsense,<IGNORE>,5,<IGNORE>,Not all parents do exist yet.\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')
+            'reg_number,code,mandatory,level,level_session,ticket_session,score,matric_number,--ERRORS--\r\n'
+            '1,COURSE1,<IGNORE>,nonsense,<IGNORE>,<IGNORE>,5,<IGNORE>,Not all parents do exist yet.\r\n'
+            '1,NONSENSE,<IGNORE>,100,<IGNORE>,<IGNORE>,5,<IGNORE>,code: non-existent\r\n'
+            '1,COURSE1,<IGNORE>,200,2004,<IGNORE>,6,<IGNORE>,level_session: does not match 2008\r\n'
+            '1,COURSE1,<IGNORE>,300,2008,<IGNORE>,6,<IGNORE>,level object: does not exist\r\n'
+            '1,COURSE1,<IGNORE>,300,2008X,<IGNORE>,6,<IGNORE>,level_session: Invalid value\r\n')
         assert self.processor.entryExists(
             dict(reg_number='1', level='100', code='COURSE1'),
@@ -1010,10 +1010,10 @@
         self.assertEqual(num_warns,5)
         self.assertEqual(fail_file,
-            'reg_number,code,mandatory,level,level_session,score,matric_number,--ERRORS--\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')
+            'reg_number,code,mandatory,level,level_session,ticket_session,score,matric_number,--ERRORS--\r\n'
+            '1,COURSE1,<IGNORE>,nonsense,<IGNORE>,<IGNORE>,5,<IGNORE>,Cannot update: no such entry\r\n'
+            '1,NONSENSE,<IGNORE>,100,<IGNORE>,<IGNORE>,5,<IGNORE>,code: non-existent\r\n'
+            '1,COURSE1,<IGNORE>,200,2004,<IGNORE>,6,<IGNORE>,level_session: does not match 2008\r\n'
+            '1,COURSE1,<IGNORE>,300,2008,<IGNORE>,6,<IGNORE>,level object: does not exist\r\n'
+            '1,COURSE1,<IGNORE>,300,2008X,<IGNORE>,6,<IGNORE>,level_session: Invalid value\r\n')
         shutil.rmtree(os.path.dirname(fin_file))
 
@@ -1052,12 +1052,12 @@
         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')
+            'reg_number,code,mandatory,level,level_session,ticket_session,score,matric_number,--ERRORS--\r\n'
+            '1,COURSE1,True,100,<IGNORE>,<IGNORE>,1,<IGNORE>,Studycourse is locked.\r\n'
+            '1,COURSE1,True,200,2008,<IGNORE>,1,<IGNORE>,Studycourse is locked.\r\n'
+            '1,COURSE1,<IGNORE>,nonsense,<IGNORE>,<IGNORE>,5,<IGNORE>,Cannot update: no such entry\r\n'
+            '1,NONSENSE,<IGNORE>,100,<IGNORE>,<IGNORE>,5,<IGNORE>,code: non-existent\r\n'
+            '1,COURSE1,<IGNORE>,200,2004,<IGNORE>,6,<IGNORE>,level_session: does not match 2008\r\n'
+            '1,COURSE1,<IGNORE>,300,2008,<IGNORE>,6,<IGNORE>,level object: does not exist\r\n'
+            '1,COURSE1,<IGNORE>,300,2008X,<IGNORE>,6,<IGNORE>,level_session: Invalid value\r\n')
         shutil.rmtree(os.path.dirname(fin_file))
 
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15203)
@@ -805,5 +805,5 @@
         self.browser.getLink("100").click()
         self.assertMatches(
-            '...: Study Level 100 (Year 1)...', self.browser.contents)
+            '...: 100 (Year 1)...', self.browser.contents)
         self.browser.getLink("Manage").click()
         self.browser.getControl(name="form.level_session").value = ['2002']
@@ -888,5 +888,5 @@
         self.browser.getLink("200").click()
         self.assertMatches(
-            '...: Study Level 200 (Year 2)...', self.browser.contents)
+            '...: 200 (Year 2)...', self.browser.contents)
         # Since COURSE1 has score 10 it becomes a carry-over course
         # in level 200
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py	(revision 15203)
@@ -614,7 +614,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '0,0,,,,,,,,0,0,,,,,,,\r\n'
+            '0,0,,,,,,,,0,0,,,,,,,,\r\n'
             )
         return
@@ -633,7 +633,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -650,7 +650,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -666,7 +666,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -685,7 +685,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -699,7 +699,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -712,7 +712,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -724,5 +724,5 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
                         )
@@ -735,5 +735,5 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
             )
@@ -747,7 +747,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,100,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -758,5 +758,5 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
             )
@@ -771,7 +771,7 @@
             result,
             'automatic,carry_over,code,course_category,credits,dcode,fcode,level,level_session,'
-            'mandatory,outstanding,passmark,score,semester,title,student_id,certcode,'
+            'mandatory,outstanding,passmark,score,semester,ticket_session,title,student_id,certcode,'
             'display_fullname\r\n'
-            '1,1,CRS1,,100,DEP1,FAC1,110,2012,0,0,100,,2,Course 1,A111111,CERT1,'
+            '1,1,CRS1,,100,DEP1,FAC1,110,2012,0,0,100,,2,,Course 1,A111111,CERT1,'
             'Anna M. Tester\r\n'
             )
@@ -1345,7 +1345,7 @@
              'student_id,state,certcode,faccode,depcode,is_postgrad,'
              'entry_session,current_level,current_session,'
-             '10,100,110,120,200,210,220,300,310,320,400,410,420,500,'
+             '0,10,100,110,120,200,210,220,300,310,320,400,410,420,500,'
              '510,520,600,610,620,700,710,720,800,810,820,900,910,920,999\r\n'
-             'A111111,created,CERT1,NA,NA,0,2010,200,2012,,2012'
+             'A111111,created,CERT1,NA,NA,0,2010,200,2012,,,2012'
              ',,,,,,,,,,,,,,,,,,,,,,,,,,,\r\n',
             result
@@ -1361,7 +1361,7 @@
             'student_id,state,certcode,faccode,depcode,is_postgrad,'
             'entry_session,current_level,current_session,'
-            '10,100,110,120,200,210,220,300,310,320,400,410,420,500,'
+            '0,10,100,110,120,200,210,220,300,310,320,400,410,420,500,'
             '510,520,600,610,620,700,710,720,800,810,820,900,910,920,999\r\n'
-            'A111111,created,CERT1,NA,NA,0,2010,200,2012,,2012'
+            'A111111,created,CERT1,NA,NA,0,2010,200,2012,,,2012'
             ',,,,,,,,,,,,,,,,,,,,,,,,,,,\r\n',
             result
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_vocabularies.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_vocabularies.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_vocabularies.py	(revision 15203)
@@ -65,14 +65,16 @@
         studylevelsource = StudyLevelSource().factory
         values = studylevelsource.getValues(studycourse)
-        self.assertEqual(values, [100, 110, 120, 200, 210, 220, 300, 310, 320,
+        self.assertEqual(values, [0, 100, 110, 120, 200, 210, 220, 300, 310, 320,
             400, 410, 420, 500, 510, 520, 600, 610, 620])
         # All titles do exist
         titles = [studylevelsource.getTitle(studycourse, value)
             for value in values]
-        self.assertEqual(len(titles), 18)
+        self.assertEqual(len(titles), 19)
         # Unfortunately, unittests don't know about internationalization
         self.assertEqual(studylevelsource.getTitle(studycourse, None),
             'Error: level id ${value} out of range')
         self.assertEqual(studylevelsource.getTitle(studycourse, 0),
+            'Level Zero')
+        self.assertEqual(studylevelsource.getTitle(studycourse, 1),
             'Error: level id ${value} out of range')
         self.assertEqual(studylevelsource.getTitle(studycourse, 10),
@@ -96,13 +98,13 @@
         self.assertEqual(studylevelsource.getTitle(studycourse, 700),
             'Error: level id ${value} out of range')
-        # Now we modify the certificates to be a pure to pre-studies
+        # Now we modify the certificates to be a pure pre-studies
         # course
         studycourse.certificate.start_level = 10
         studycourse.certificate.end_level = 10
         values = studylevelsource.getValues(studycourse)
-        self.assertEqual(values, [10])
+        self.assertEqual(values, [0, 10])
         titles = [studylevelsource.getTitle(studycourse, value)
             for value in values]
-        self.assertEqual(len(titles), 1)
+        self.assertEqual(len(titles), 2)
         self.assertEqual(studylevelsource.getTitle(studycourse, 10),
             'Pre-Studies')
@@ -115,9 +117,9 @@
         studycourse.certificate.end_level = 200
         values = studylevelsource.getValues(studycourse)
-        self.assertEqual(values, [10, 100, 110, 120,
+        self.assertEqual(values, [0, 10, 100, 110, 120,
             200, 210, 220, 300, 310, 320])
         titles = [studylevelsource.getTitle(studycourse, value)
             for value in values]
-        self.assertEqual(len(titles), 10)
+        self.assertEqual(len(titles), 11)
         # Repeating Pre-Studies level does not exist and raises a KeyError
         # when trying to get its title
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py	(revision 15203)
@@ -263,9 +263,15 @@
         headerline = []
         tabledata = []
-        subheader = '%s %s, %s %s' % (
-            trans(_('Session'), lang),
-            view.session_dict[level_obj.level_session],
-            trans(_('Level'), lang),
-            view.level_dict[level_obj.level])
+        if 'evel' in view.level_dict.get('ticket.level', str(level_obj.level)):
+            subheader = '%s %s, %s' % (
+                trans(_('Session'), lang),
+                view.session_dict[level_obj.level_session],
+                view.level_dict.get('ticket.level', str(level_obj.level)))
+        else:
+            subheader = '%s %s, %s %s' % (
+                trans(_('Session'), lang),
+                view.session_dict[level_obj.level_session],
+                trans(_('Level'), lang),
+                view.level_dict.get('ticket.level', str(level_obj.level)))
         data.append(Paragraph(subheader, HEADING_STYLE))
         for element in tableheader:
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/vocabularies.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/vocabularies.py	(revision 15200)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/vocabularies.py	(revision 15203)
@@ -69,5 +69,5 @@
         start_level = int(certificate.start_level)
         end_level = int(certificate.end_level)
-    return levels_from_range(start_level, end_level)
+    return [0,] + levels_from_range(start_level, end_level)
 
 class StudyLevelSource(BasicContextualSourceFactory):
@@ -77,4 +77,6 @@
     first spillover level by the certificate's end level plus 100
     and the second spillover level by the end level plus 110.
+    The level zero contains all courses without level
+    affiliation.
     """
     def getValues(self, context):
@@ -105,4 +107,6 @@
         if value == 999:
             return course_levels.by_value[999].title
+        if value == 0:
+            return _('Level Zero')
         if start_level == 10 and end_level == 10 and value != 10:
             return _('Error: level id ${value} out of range',
