Index: main/waeup.kofa/trunk/CHANGES.txt
===================================================================
--- main/waeup.kofa/trunk/CHANGES.txt	(revision 15917)
+++ main/waeup.kofa/trunk/CHANGES.txt	(revision 15918)
@@ -4,4 +4,6 @@
 1.6.1.dev0 (unreleased)
 =======================
+
+* Add `session_level`filter to `StudentStudyLevelExporter`.
 
 * Add LetterPDFCreator utility and use this pdf creator
Index: main/waeup.kofa/trunk/docs/source/userdocs/datacenter/export.rst
===================================================================
--- main/waeup.kofa/trunk/docs/source/userdocs/datacenter/export.rst	(revision 15917)
+++ main/waeup.kofa/trunk/docs/source/userdocs/datacenter/export.rst	(revision 15918)
@@ -222,5 +222,5 @@
 
 Student Outstanding Courses Exporter
-----------------------
+------------------------------------
 
 .. autoclass:: waeup.kofa.students.export.StudentOutstandingCoursesExporter()
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_export.py	(revision 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_export.py	(revision 15918)
@@ -50,15 +50,15 @@
     def setup_container(self, container):
         # set all attributes of a container
-        container.code = u'dp2015'
+        container.code = u'dp2017'
         container.title = u'General Studies'
         container.prefix = list(ApplicationTypeSource()(container))[0]
-        container.year = 2015
+        container.year = 2017
         container.application_category = list(AppCatSource()(container))[0]
         container.description = u'Some Description\nwith linebreak\n'
         container.description += u'<<de>>man spriht deutsh'
         container.startdate = datetime.datetime(
-            2015, 1, 1, 12, 0, 0, tzinfo=pytz.utc)
+            2017, 1, 1, 12, 0, 0, tzinfo=pytz.utc)
         container.enddate = datetime.datetime(
-            2015, 1, 31, 23, 0, 0, tzinfo=pytz.utc)
+            2017, 1, 31, 23, 0, 0, tzinfo=pytz.utc)
         return container
 
@@ -76,8 +76,8 @@
             'strict_deadline,title,with_picture,year\r\n'
 
-            'basic,0.0,,dp2015,'
+            'basic,0.0,,dp2017,'
             '"Some Description\nwith linebreak\n<<de>>man spriht deutsh",'
-            '2015-01-31 23:00:00+00:00#,0,,app,2015-01-01 12:00:00+00:00#,1,'
-            'General Studies,1,2015\r\n'
+            '2017-01-31 23:00:00+00:00#,0,,app,2017-01-01 12:00:00+00:00#,1,'
+            'General Studies,1,2017\r\n'
             )
         return
Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py	(revision 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py	(revision 15918)
@@ -449,5 +449,5 @@
             'zope.mgr - students.browser.DatacenterExportJobContainerJobConfig '
             '- exported: students '
-            '(None, None, None, None, None, None, , , all, all, all, all), '
+            '(None, None, None, None, None, None, , , all, all, all, all, all), '
             'job_id=%s'
             % job_id in logcontent)
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15918)
@@ -3959,5 +3959,5 @@
                payments_start=None, payments_end=None, ct_level=None, 
                ct_session=None, ct_semester=None, paycat=None,
-               paysession=None, exporter=None):
+               paysession=None, level_session=None, exporter=None):
         self._set_session_values()
         self._set_level_values()
@@ -4003,4 +4003,5 @@
                                           ct_session = ct_session,
                                           ct_semester = ct_semester,
+                                          level_session=level_session,
                                           )
         else:
@@ -4019,11 +4020,12 @@
                                           ct_level = ct_level,
                                           ct_session = ct_session,
-                                          ct_semester = ct_semester,)
+                                          ct_semester = ct_semester,
+                                          level_session=level_session,)
         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
         self.context.logger.info(
-            '%s - exported: %s (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s), job_id=%s'
+            '%s - exported: %s (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s), job_id=%s'
             % (ob_class, exporter, session, level, mode, self.faccode,
             self.depcode, self.certcode, payments_start, payments_end,
-            ct_level, ct_session, paycat, paysession, job_id))
+            ct_level, ct_session, paycat, paysession, level_session, job_id))
         self.flash(_('Export started for students with') +
                    ' current_session=%s, current_level=%s, study_mode=%s' % (
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportconfig.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportconfig.pt	(revision 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/exportconfig.pt	(revision 15918)
@@ -95,4 +95,18 @@
   </span>
 
+  <span id="level_session" style="display: none;">
+    <br />
+    <label for="level_session" i18n:translate="">
+      Level Session
+    </label>
+    <select name="level_session" class="form-control half">
+      <option tal:repeat="item view/sessions"
+              tal:attributes="value python:item[1]">
+        <span tal:replace="python: item[0]">2018/2019</span>
+      </option>
+    </select>
+    <br />
+  </span>
+
   <span id="ct_data" style="display: none;">
     <br />
@@ -144,6 +158,7 @@
           document.getElementById('payment_dates').style.display = 'block';
           document.getElementById('paycat').style.display = 'block';
+          document.getElementById('paysession').style.display = 'block';
           document.getElementById('ct_data').style.display = 'none';
-          document.getElementById('paysession').style.display = 'block';
+          document.getElementById('level_session').style.display = 'none';
 
       } else if (document.getElementById('exporter').value == 'coursetickets')  {
@@ -152,4 +167,12 @@
           document.getElementById('paycat').style.display = 'none';
           document.getElementById('paysession').style.display = 'none';
+          document.getElementById('level_session').style.display = 'none';
+
+      } else if (document.getElementById('exporter').value == 'studentstudylevels')  {
+          document.getElementById('ct_data').style.display = 'none';
+          document.getElementById('payment_dates').style.display = 'none';
+          document.getElementById('paycat').style.display = 'none';
+          document.getElementById('paysession').style.display = 'none';
+          document.getElementById('level_session').style.display = 'block';
 
       } else {
@@ -158,4 +181,5 @@
           document.getElementById('paycat').style.display = 'none';
           document.getElementById('paysession').style.display = 'none';
+          document.getElementById('level_session').style.display = 'none';
       }
   }
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/export.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/export.py	(revision 15918)
@@ -46,10 +46,14 @@
             if x is not None]
 
-def get_levels(students):
+def get_levels(students, **kw):
     """Get all studylevels of `students`.
     """
     levels = []
+    level_session = kw.get('level_session', None)
     for course in get_studycourses(students):
         for level in course.values():
+            if level_session not in ('all', None) and \
+                int(level_session) != level.level_session:
+                continue
             levels.append(level)
     return levels
@@ -73,5 +77,5 @@
     ct_semester = kw.get('ct_semester', None)
     if code is None:
-        for level_obj in get_levels(students):
+        for level_obj in get_levels(students, **kw):
             for ticket in level_obj.values():
                 if ct_level not in ('all', None):
@@ -90,5 +94,5 @@
                 tickets.append(ticket)
     else:
-        for level_obj in get_levels(students):
+        for level_obj in get_levels(students, **kw):
             for ticket in level_obj.values():
                 if ticket.code != code:
@@ -116,5 +120,5 @@
     level_session = kw.get('session', None)
     level = kw.get('level', None)
-    for level_obj in get_levels(students):
+    for level_obj in get_levels(students, **kw):
         for ticket in level_obj.values():
             if ticket.code != code:
@@ -253,4 +257,11 @@
         except KeyError:
             pass
+        # Studylevels can be filtered by level_session.
+        # This parameter is not a key of the catalog and must thus be
+        # removed from kw.
+        try:
+            del kw['level_session']
+        except KeyError:
+            pass
         query = StudentsQuery(**kw)
         return query.query()
@@ -378,5 +389,5 @@
 
     def filter_func(self, x, **kw):
-        return get_levels(x)
+        return get_levels(x, **kw)
 
     def mangle_value(self, value, name, context=None):
@@ -705,5 +716,5 @@
         paycatyears = []
         if cas:
-            year_range = range(cas - 2, cas+1)
+            year_range = range(cas-2, cas+1)
             year_range_tuple = tuple([str(year)[2:] for year in year_range])
             paycatyears = [
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 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15918)
@@ -3760,5 +3760,5 @@
             'zope.mgr - students.browser.DatacenterExportJobContainerJobConfig '
             '- exported: bursary (2004, 100, ug_ft, None, None, None, '
-            '13/12/2012, 14/12/2012, all, all, all, all), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, all, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -3843,7 +3843,8 @@
             self.browser.headers['content-disposition'])
         self.assertTrue(
-            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,2013,'
+            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,%s,'
             'paid,2012-12-13 00:00:00#,12.12,r-code,,K1000000,234,123,Anna,,'
-            'Tester,created,2004,2004,,fac1,dep1,CERT1' in self.browser.contents)
+            'Tester,created,2004,2004,,fac1,dep1,CERT1'
+            %(curr_year-6) in self.browser.contents)
         self.assertEqual(len(self.app['datacenter'].running_exports), 1)
         job_id = self.app['datacenter'].running_exports[0][0]
@@ -3859,5 +3860,5 @@
             'zope.mgr - students.browser.FacultiesExportJobContainerJobConfig '
             '- exported: bursary (2004, 100, ug_ft, None, None, None, '
-            '13/12/2012, 14/12/2012, all, all, schoolfee, all), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, schoolfee, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -3889,7 +3890,8 @@
             self.browser.headers['content-disposition'])
         self.assertTrue(
-            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,2013,'
+            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,%s,'
             'paid,2012-12-13 00:00:00#,12.12,r-code,,K1000000,234,123,Anna,,'
-            'Tester,created,2004,2004,,fac1,dep1,CERT1' in self.browser.contents)
+            'Tester,created,2004,2004,,fac1,dep1,CERT1'
+            %(curr_year-6) in self.browser.contents)
 
     def test_faculty_export(self):
@@ -3941,5 +3943,5 @@
             'zope.mgr - students.browser.FacultyExportJobContainerJobConfig '
             '- exported: students (2004, 100, ug_ft, fac1, None, None, '
-            '13/12/2012, 14/12/2012, all, all, all, all), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, all, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -4000,5 +4002,5 @@
             'zope.mgr - students.browser.DepartmentExportJobContainerJobConfig '
             '- exported: students (2004, 100, ug_ft, None, dep1, None, '
-            '13/12/2012, 14/12/2012, all, all, all, all), job_id=%s'
+            '13/12/2012, 14/12/2012, all, all, all, all, all), job_id=%s'
             % job_id in logcontent
             )
@@ -4047,5 +4049,6 @@
             'zope.mgr - students.browser.CertificateExportJobContainerJobConfig '
             '- exported: students '
-            '(2004, 100, None, None, None, CERT1, , , None, None, None, None), '
+            '(2004, 100, None, None, None, CERT1, , , None, None, '
+            'None, None, None), '
             'job_id=%s'
             % job_id in logcontent
@@ -4246,7 +4249,8 @@
             self.browser.headers['content-disposition'])
         self.assertTrue(
-            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,2013,'
+            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,%s,'
             'paid,2012-12-13 00:00:00#,12.12,r-code,,K1000000,234,123,Anna,,'
-            'Tester,created,2004,2004,,fac1,dep1,CERT1' in self.browser.contents)
+            'Tester,created,2004,2004,,fac1,dep1,CERT1'
+            %(curr_year-6) in self.browser.contents)
         # ... and discarded
         self.browser.open('http://localhost/app/faculties/exports')
@@ -4272,7 +4276,8 @@
             self.browser.headers['content-disposition'])
         self.assertTrue(
-            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,2013,'
+            '666,12.12,2012-12-13 00:00:00#,schoolfee,[],1,my-id,p-item,100,%s,'
             'paid,2012-12-13 00:00:00#,12.12,r-code,,K1000000,234,123,Anna,,'
-            'Tester,created,2004,2004,,fac1,dep1,CERT1' in self.browser.contents)
+            'Tester,created,2004,2004,,fac1,dep1,CERT1'
+            %(curr_year-6) in self.browser.contents)
 
     def test_export_accommodation_officers(self):
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 15917)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_export.py	(revision 15918)
@@ -1365,5 +1365,13 @@
         super(SessionPaymentsOverviewExporterTest, self).setUp()
         self.setup_for_export()
+        paycats = ('schoolfee', 'clearance', 'gown', 'transcript')
+        paycatyears = ''
         grok.getSite()['configuration'].current_academic_session = curr_year - 4
+        year_range = range(curr_year-6, curr_year-3)
+        year_range_tuple = tuple([str(year)[2:] for year in year_range])
+        for cat in paycats:
+            for year in year_range_tuple:
+                paycatyears += '%s,'%(cat+str(year))
+        self.paycatyears = paycatyears.strip(',')
         return
 
@@ -1389,10 +1397,8 @@
             'student_id,matric_number,display_fullname,state,certcode,'
             'faccode,depcode,is_postgrad,current_level,current_session,'
-            'current_mode,entry_session,reg_number,schoolfee13,'
-            'schoolfee14,schoolfee15,clearance13,clearance14,clearance15,'
-            'gown13,gown14,gown15,transcript13,transcript14,transcript15\r\n'
+            'current_mode,entry_session,reg_number,%s\r\n'
             'A111111,234,Anna M. Tester,created,CERT1,NA,NA,0,200,'
             '2012,ug_ft,2010,123,'
-            '12.12,,,,,,,,,,,\r\n' in result
+            '12.12,,,,,,,,,,,\r\n' %self.paycatyears in result
             )
         return
@@ -1431,13 +1437,9 @@
             'student_id,matric_number,display_fullname,state,certcode,faccode,'
             'depcode,is_postgrad,current_level,current_session,'
-            'current_mode,entry_session,reg_number,'
-            'schoolfee13,schoolfee14,schoolfee15,'
-            'clearance13,clearance14,clearance15,'
-            'gown13,gown14,gown15,'
-            'transcript13,transcript14,transcript15\r\n'
+            'current_mode,entry_session,reg_number,%s\r\n'
             'A111111,234,Anna M. Tester,created,CERT1,NA,NA,0,200,2012,ug_ft,'
             '2010,123,'
             '12.12,14.14,1.01,,,,,,,,,\r\n'
-            in result
+            %self.paycatyears in result
             )
         return
