Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/browser_templates/levelreportgeneratorpage.pt
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/browser_templates/levelreportgeneratorpage.pt	(revision 14422)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/browser_templates/levelreportgeneratorpage.pt	(revision 14423)
@@ -7,7 +7,14 @@
   </p>
   <br />
-  <label for="session" i18n:translate="">Department</label>
-  <select name="faccode_depcode" class="form-control half">
-    <span tal:repeat="items view/faccode_depcodes" tal:omit-tag="">
+
+  <label for="session" i18n:translate="">Certificate</label>
+  <input id="filterbox" class="kofa-filterbox form-control half"
+         placeholder="Enter search text, then select item below."
+         type="text" i18n:translate=""/>
+  <br />
+  <select id="filteredselect" name="faccode_depcode_certcode"
+          class="form-control half" size=5>
+      <span tal:repeat="items view/faccode_depcode_certcode"
+          tal:omit-tag="">
       <option
           tal:define="name python: items[1]; title python: items[0]"
@@ -19,15 +26,13 @@
   <br />
   <label for="session">Academic Session</label>
-  <div class="input">
-    <select name="session" class="form-control half">
-      <span tal:repeat="items view/sessions" tal:omit-tag="">
-        <option
-            tal:define="name python: items[1]; title python: items[0]"
-            tal:attributes="value name">
-          <span tal:replace="title">TITLE</span>
-        </option>
-      </span>
-    </select>
-  </div>
+  <select name="session" class="form-control half">
+    <span tal:repeat="items view/sessions" tal:omit-tag="">
+      <option
+          tal:define="name python: items[1]; title python: items[0]"
+          tal:attributes="value name">
+        <span tal:replace="title">TITLE</span>
+      </option>
+    </span>
+  </select>
   <br />
   <label for="session">Level</label>
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/level_report.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/level_report.py	(revision 14422)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/level_report.py	(revision 14423)
@@ -38,9 +38,10 @@
     faccode = Attribute('Faculty to report')
     depcode = Attribute('Department to report')
+    certcode = Attribute('Certificate to report')
     creation_dt_string = Attribute('Human readable report creation datetime')
 
-def get_students(faccode, depcode, session, level):
-    """Get students in a certain department who registered courses
-    in a certain session at a certain level.
+def get_students(faccode, depcode, certcode, session, level):
+    """Get students in a certain department, studying a certain programmen
+    who registered courses in a certain session at a certain level.
 
     Returns a list of student data tuples.
@@ -48,6 +49,9 @@
     site = grok.getSite()
     cat = queryUtility(ICatalog, name="students_catalog")
+    if certcode == 'all':
+        certcode = None
     result = cat.searchResults(
-        depcode = (depcode, depcode), faccode = (faccode, faccode)
+        depcode = (depcode, depcode), faccode = (faccode, faccode),
+        certcode = (certcode, certcode)
         )
     table = []
@@ -171,10 +175,13 @@
     faccode = None
     depcode = None
+    certcode = None
 
     note = None
 
-    def __init__(self, faccode, depcode, session, level, author='System'):
+    def __init__(self, faccode, depcode, certcode, session, level,
+                 author='System'):
         super(LevelReport, self).__init__(
-            args=[faccode, depcode, session, level], kwargs={'author':author})
+            args=[faccode, depcode, certcode, session, level],
+            kwargs={'author':author})
         site = grok.getSite()
         self.studylevelsource = StudyLevelSource().factory
@@ -187,10 +194,18 @@
         self.faccode = faccode
         self.depcode = depcode
+        self.certcode = certcode
         self.factitle = site['faculties'][faccode].longtitle
         self.deptitle = site['faculties'][faccode][depcode].longtitle
+        if self.certcode == 'all':
+            self.certtitle = translate(
+                _('All Certificates'), 'waeup.kofa',
+                target_language=self.portal_language)
+        else:
+            self.certtitle = site['faculties'][faccode][
+                depcode].certificates[certcode].longtitle
         self.author = author
         self.creation_dt_string = self.creation_dt.astimezone(
             getUtility(IKofaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z")
-        self.data = get_students(faccode, depcode, session, level)
+        self.data = get_students(faccode, depcode, certcode, session, level)
 
     def create_pdf(self, job_id):
@@ -206,9 +221,10 @@
         pdf_data += [Paragraph(
                     translate(
-                        '${a}<br />${b}<br />Session: ${c}<br />Level: ${d}',
-                        mapping = {'a':self.factitle,
+                        '${a}<br />${b}<br />${c}<br /><br />Session: ${d}<br />Level: ${e}',
+                        mapping = {'a':self.certtitle,
                                    'b':self.deptitle,
-                                   'c':self.session,
-                                   'd':self.level,
+                                   'c':self.factitle,
+                                   'd':self.session,
+                                   'e':self.level,
                                    }),
                     STYLE["Normal"]),
@@ -227,6 +243,7 @@
         pdf = creator.create_pdf(
             pdf_data, None, doc_title, self.author,
-            doc_title + ' - %s/%s - %s - %s -' % (
-            self.faccode, self.depcode, self.levelcode, self.sessioncode),
+            doc_title + ' - %s/%s/%s - %s - %s -' % (
+            self.faccode, self.depcode, self.certcode,
+            self.levelcode, self.sessioncode),
             note = self.note
             )
@@ -239,7 +256,8 @@
     grok.name('level_report')
 
-    def generate(self, site, faccode=None, depcode=None,
+    def generate(self, site, faccode=None, depcode=None, certcode=None,
                  session=None, level=None, author=None):
         result = LevelReport(faccode=faccode, depcode=depcode,
+                             certcode=certcode,
                              session=session, level=level, author=author)
         return result
@@ -270,14 +288,18 @@
         return None
 
-    def update(self, CREATE=None, faccode_depcode=None,
+    def update(self, CREATE=None, faccode_depcode_certcode=None,
                session=None, level=None):
         self.parent_url = self.url(self.context.__parent__)
         self._set_session_values()
         self._set_level_values()
-        self._set_faccode_depcode_values()
-        if CREATE and session:
+        self._set_faccode_depcode_certcode_values()
+        if not faccode_depcode_certcode:
+            self.flash(_('No certificate selected.'), type="warning")
+            return
+        if CREATE:
             # create a new report job for students by session
-            faccode = faccode_depcode.split('_')[0]
-            depcode = faccode_depcode.split('_')[1]
+            faccode = faccode_depcode_certcode.split('_')[0]
+            depcode = faccode_depcode_certcode.split('_')[1]
+            certcode = faccode_depcode_certcode.split('_')[2]
             container = self.context.__parent__
             user_id = self.request.principal.id
@@ -290,5 +312,6 @@
                 level=level,
                 faccode=faccode,
-                depcode=depcode)
+                depcode=depcode,
+                certcode=certcode)
             self.flash(_('New report is being created in background'))
             job_id = container.start_report_job(
@@ -296,6 +319,7 @@
             ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
             grok.getSite().logger.info(
-                '%s - report %s created: %s (faculty=%s, department=%s, session=%s, level=%s)' % (
-                ob_class, job_id, self.context.title, faccode, depcode, session, level))
+                '%s - report %s created: %s (faculty=%s, department=%s, certificate=%s, session=%s, level=%s)' % (
+                ob_class, job_id, self.context.title, faccode, depcode,
+                certcode, session, level))
             self.redirect(self.parent_url)
             return
@@ -322,14 +346,22 @@
         return
 
-    def _set_faccode_depcode_values(self):
-        faccode_depcodes = []
+    def _set_faccode_depcode_certcode_values(self):
+        faccode_depcode_certcode = []
         faculties = grok.getSite()['faculties']
         for fac in faculties.values():
             for dep in fac.values():
-                faccode_depcodes.append(
-                    ('%s (%s)' %(dep.longtitle, fac.longtitle),
-                     '%s_%s' %(fac.code, dep.code)))
-        self.faccode_depcodes = sorted(
-            faccode_depcodes, key=lambda value: value[0])
+                faccode_depcode_certcode.append(
+                    ('All certificates -- %s, %s)'
+                     %(dep.longtitle, fac.longtitle),
+                     '%s_%s_all'
+                     %(fac.code, dep.code)))
+                for cert in dep.certificates.values():
+                    faccode_depcode_certcode.append(
+                        ('%s -- %s, %s)'
+                         %(cert.longtitle, dep.longtitle, fac.longtitle),
+                         '%s_%s_%s'
+                         %(fac.code, dep.code, cert.code)))
+        self.faccode_depcode_certcode = sorted(
+            faccode_depcode_certcode, key=lambda value: value[0])
         return
 
@@ -342,6 +374,6 @@
 
     def _filename(self):
-        return 'LevelReport_%s_%s_%s_%s_%s.pdf' % (
-            self.context.faccode, self.context.depcode,
+        return 'LevelReport_%s_%s_%s_%s_%s_%s.pdf' % (
+            self.context.faccode, self.context.depcode, self.context.certcode,
             self.context.sessioncode, self.context.levelcode,
             self.context.creation_dt_string)
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/session_results_presentation.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/session_results_presentation.py	(revision 14422)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/session_results_presentation.py	(revision 14423)
@@ -40,7 +40,7 @@
     """
 
-def get_students(faccode, depcode, session, level=None):
-    """Get students in a certain department who registered courses
-    in a certain session at a certain level.
+def get_students(faccode, depcode, certcode, session, level=None):
+    """Get students in a certain department, studying a certain programmen
+    who registered courses in a certain session at a certain level.
 
     Returns a list of lists of student data tuples.
@@ -48,6 +48,9 @@
     site = grok.getSite()
     cat = queryUtility(ICatalog, name="students_catalog")
+    if certcode == 'all':
+        certcode = None
     result = cat.searchResults(
-        depcode = (depcode, depcode), faccode = (faccode, faccode)
+        depcode = (depcode, depcode), faccode = (faccode, faccode),
+        certcode = (certcode, certcode)
         )
     students_utils = getUtility(IStudentsUtils)
@@ -117,10 +120,13 @@
     faccode = None
     depcode = None
+    certcode = None
 
     note = None
 
-    def __init__(self, faccode, depcode, session, level, author='System'):
+    def __init__(self, faccode, depcode, certcode, session, level,
+                 author='System'):
         super(SessionResultsPresentation, self).__init__(
-            args=[faccode, depcode, session, level], kwargs={'author':author})
+            args=[faccode, depcode, certcode, session, level],
+            kwargs={'author':author})
         site = grok.getSite()
         self.studylevelsource = StudyLevelSource().factory
@@ -136,10 +142,18 @@
         self.faccode = faccode
         self.depcode = depcode
+        self.certcode = certcode
         self.factitle = site['faculties'][faccode].longtitle
         self.deptitle = site['faculties'][faccode][depcode].longtitle
+        if self.certcode == 'all':
+            self.certtitle = translate(
+                _('All Certificates'), 'waeup.kofa',
+                target_language=self.portal_language)
+        else:
+            self.certtitle = site['faculties'][faccode][
+                depcode].certificates[certcode].longtitle
         self.author = author
         self.creation_dt_string = self.creation_dt.astimezone(
             getUtility(IKofaUtils).tzinfo).strftime("%Y-%m-%d %H:%M:%S %Z")
-        self.data = get_students(faccode, depcode, session, level)
+        self.data = get_students(faccode, depcode, certcode, session, level)
 
     def create_pdf(self, job_id):
@@ -150,6 +164,13 @@
                               STYLE["Normal"]),
                     Spacer(1, 12),]
-        pdf_data += [Paragraph('%s<br />%s<br />Session: %s<br />Level: %s' % (
-                    self.factitle, self.deptitle, self.session, self.level),
+        pdf_data += [Paragraph(
+                    translate(
+                        '${a}<br />${b}<br />${c}<br /><br />Session: ${d}<br />Level: ${e}',
+                        mapping = {'a':self.certtitle,
+                                   'b':self.deptitle,
+                                   'c':self.factitle,
+                                   'd':self.session,
+                                   'e':self.level,
+                                   }),
                     STYLE["Normal"]),
                     Spacer(1, 12),]
@@ -197,6 +218,7 @@
         pdf = creator.create_pdf(
             pdf_data, None, doc_title, self.author,
-            doc_title + ' - %s/%s - %s - %s -' % (
-            self.faccode, self.depcode, self.levelcode, self.sessioncode),
+            doc_title + ' - %s/%s/%s - %s - %s -' % (
+            self.faccode, self.depcode, self.certcode,
+            self.levelcode, self.sessioncode),
             note = self.note
             )
@@ -209,8 +231,8 @@
     grok.name('session_results_presentation')
 
-    def generate(self, site, faccode=None, depcode=None,
+    def generate(self, site, faccode=None, depcode=None, certcode=None,
                  session=None, level=None, author=None):
         result = SessionResultsPresentation(faccode=faccode, depcode=depcode,
-                             session=session, level=level, author=author)
+                 certcode=certcode, session=session, level=level, author=author)
         return result
 
@@ -230,15 +252,4 @@
     grok.template('levelreportgeneratorpage')
     label = _('Create session results presentation')
-
-    def update(self, CREATE=None, faccode_depcode=None,
-               session=None, level=None):
-        super(SessionResultsPresentationGeneratorPage, self).update(
-            CREATE, faccode_depcode ,session, level)
-
-    #def _set_level_values(self):
-    #    vocab_terms = course_levels.by_value.values()
-    #    self.levels = [('All levels', 'all')] + sorted(
-    #        [(x.title, x.token) for x in vocab_terms])
-    #    return
 
     def _set_level_values(self):
@@ -260,6 +271,6 @@
 
     def _filename(self):
-        return 'SessionResultsPresentation_%s_%s_%s_%s_%s.pdf' % (
-            self.context.faccode, self.context.depcode,
+        return 'SessionResultsPresentation_%s_%s_%s_%s_%s_%s.pdf' % (
+            self.context.faccode, self.context.depcode, self.context.certcode,
             self.context.sessioncode, self.context.levelcode,
             self.context.creation_dt_string)
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/tests/test_level_report.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/tests/test_level_report.py	(revision 14422)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/tests/test_level_report.py	(revision 14423)
@@ -18,5 +18,5 @@
     def test_iface(self):
         # ensure we fullfill interface contracts
-        obj = LevelReport('fac1', 'dep1', 2010, 100)
+        obj = LevelReport('fac1', 'dep1', 'CERT1', 2010, 100)
         verifyClass(ILevelReport, LevelReport)
         verifyObject(ILevelReport, obj)
@@ -39,5 +39,10 @@
         self.student['studycourse']['100']['Course3'] = ticket
         # we can get a table with one student
-        result = get_students('fac1', 'dep1', 2010, 100)
+        result = get_students('fac1', 'dep1', 'CERT1', 2010, 100)
+        self.assertEqual(result,
+            [(u'1234', u'Bob Tester', 90, 30, '1.666',
+            'm_Course2_m Course3', '', 90, 30, '1.666', '')])
+        # same result when selecting all certificates
+        result = get_students('fac1', 'dep1', 'all', 2010, 100)
         self.assertEqual(result,
             [(u'1234', u'Bob Tester', 90, 30, '1.666',
@@ -72,5 +77,5 @@
         ticket4.credits = 30
         self.student['studycourse']['100']['Course6'] = ticket4
-        report = LevelReport('fac1', 'dep1', 2010, 100)
+        report = LevelReport('fac1', 'dep1', 'all', 2010, 100)
         result = report.create_pdf('JOB_ID')
         self.assertTrue(result.startswith('%PDF-'))
@@ -108,5 +113,6 @@
         self.browser.getControl(name="level").value = ['100']
         self.browser.getControl(name="session").value = ['2010']
-        self.browser.getControl(name="faccode_depcode").value = ['fac1_dep1']
+        self.browser.getControl(name="faccode_depcode_certcode").value = [
+            'fac1_dep1_CERT1']
         self.browser.getControl("Create").click()
         return
@@ -123,5 +129,5 @@
                          'application/pdf')
         self.assertTrue(
-            'filename="LevelReport_fac1_dep1_2010_100_' in
+            'filename="LevelReport_fac1_dep1_CERT1_2010_100_' in
             self.browser.headers['content-disposition'])
         self.assertEqual(len(self.app['reports'].running_report_jobs), 1)
@@ -137,10 +143,11 @@
         self.assertTrue(
             'INFO - zope.mgr - students.reports.level_report.LevelReportGeneratorPage - '
-            'report %s created: Level Report (faculty=fac1, department=dep1, session=2010, level=100)'
+            'report %s created: Level Report (faculty=fac1, department=dep1, '
+            'certificate=CERT1, session=2010, level=100)'
             % job_id in logcontent
             )
         self.assertTrue(
             'INFO - zope.mgr - students.reports.level_report.LevelReportPDFView - '
-            'report %s downloaded: LevelReport_fac1_dep1_2010_100_'
+            'report %s downloaded: LevelReport_fac1_dep1_CERT1_2010_100_'
             % job_id in logcontent
             )
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/tests/test_session_results_presentation.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/tests/test_session_results_presentation.py	(revision 14422)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/reports/tests/test_session_results_presentation.py	(revision 14423)
@@ -20,5 +20,5 @@
     def test_iface(self):
         # ensure we fullfill interface contracts
-        obj = SessionResultsPresentation('fac1', 'dep1', 2010, 100)
+        obj = SessionResultsPresentation('fac1', 'dep1', 'CERT1', 2010, 100)
         verifyClass(ISessionResultsPresentation, SessionResultsPresentation)
         verifyObject(ISessionResultsPresentation, obj)
@@ -26,5 +26,5 @@
 
     def test_get_students(self):
-        result = get_students('fac1', 'dep1', 2010, 100)
+        result = get_students('fac1', 'dep1', 'CERT1', 2010, 100)
         self.assertEqual(result,
             [[], [], [], [], [], [(u'K1000000', u'1234', u'Bob Tester')], []])
@@ -32,5 +32,11 @@
 
     def test_get_students_at_all_levels(self):
-        result = get_students('fac1', 'dep1', 2010, 0)
+        result = get_students('fac1', 'dep1', 'CERT1', 2010, 0)
+        self.assertEqual(result,
+            [[], [], [], [], [], [(u'K1000000', u'1234', u'Bob Tester')], []])
+        return
+
+    def test_get_students_all_certs(self):
+        result = get_students('fac1', 'dep1', 'all', 2010, 100)
         self.assertEqual(result,
             [[], [], [], [], [], [(u'K1000000', u'1234', u'Bob Tester')], []])
@@ -43,5 +49,5 @@
         studylevel.level_session = 2010
         self.student['studycourse']['200'] = studylevel
-        result = get_students('fac1', 'dep1', 2010, 0)
+        result = get_students('fac1', 'dep1', 'CERT1', 2010, 0)
         self.assertEqual(result,
             [[], [], [], [], [], [], [(u'K1000000', u'1234', u'Bob Tester')]])
@@ -50,5 +56,5 @@
     def test_get_students_without_scores(self):
         self.student['studycourse']['100']['Course1'].score = None
-        result = get_students('fac1', 'dep1', 2010, 0)
+        result = get_students('fac1', 'dep1', 'CERT1', 2010, 0)
         self.assertEqual(result,
             [[], [], [], [], [], [], [(u'K1000000', u'1234', u'Bob Tester')]])
@@ -56,5 +62,5 @@
     def test_get_students_without_level_in_session(self):
         self.student['studycourse']['100'].level_session = 2011
-        result = get_students('fac1', 'dep1', 2010)
+        result = get_students('fac1', 'dep1', 'CERT1', 2010)
         self.assertEqual(result,
             [[], [], [], [], [], [], []])
@@ -62,5 +68,5 @@
 
     def test_create_pdf(self):
-        report = SessionResultsPresentation('fac1', 'dep1', 2010, 100)
+        report = SessionResultsPresentation('fac1', 'dep1', 'CERT1', 2010, 100)
         result = report.create_pdf('JOB_ID')
         self.assertTrue(result.startswith('%PDF-'))
@@ -80,5 +86,5 @@
         self.student['studycourse']['620'] = studylevel
         self.student['studycourse']['620']['Course2'] = ticket
-        report = SessionResultsPresentation('fac1', 'dep1', 2013, 620)
+        report = SessionResultsPresentation('fac1', 'dep1', 'CERT1', 2013, 620)
         result = report.create_pdf('JOB_ID')
         self.assertTrue(result.startswith('%PDF-'))
@@ -101,5 +107,5 @@
         self.student['studycourse']['200'] = studylevel
         self.student['studycourse']['200']['Course2'] = ticket
-        report = SessionResultsPresentation('fac1', 'dep1', 2010, 0)
+        report = SessionResultsPresentation('fac1', 'dep1', 'CERT1', 2010, 0)
         result = report.create_pdf('JOB_ID')
         self.assertTrue(result.startswith('%PDF-'))
@@ -137,5 +143,5 @@
         self.browser.getControl(name="level").value = [level]
         self.browser.getControl(name="session").value = ['2010']
-        self.browser.getControl(name="faccode_depcode").value = ['fac1_dep1']
+        self.browser.getControl(name="faccode_depcode_certcode").value = ['fac1_dep1_CERT1']
         self.browser.getControl("Create").click()
         return
@@ -152,5 +158,5 @@
                          'application/pdf')
         self.assertTrue(
-            'filename="SessionResultsPresentation_fac1_dep1_2010_100_' in
+            'filename="SessionResultsPresentation_fac1_dep1_CERT1_2010_100_' in
             self.browser.headers['content-disposition'])
         self.assertEqual(len(self.app['reports'].running_report_jobs), 1)
@@ -166,10 +172,11 @@
         self.assertTrue(
             'INFO - zope.mgr - students.reports.session_results_presentation.SessionResultsPresentationGeneratorPage - '
-            'report %s created: Session Results Presentation (faculty=fac1, department=dep1, session=2010, level=100)'
+            'report %s created: Session Results Presentation '
+            '(faculty=fac1, department=dep1, certificate=CERT1, session=2010, level=100)'
             % job_id in logcontent
             )
         self.assertTrue(
             'INFO - zope.mgr - students.reports.session_results_presentation.SessionResultsPresentationPDFView - '
-            'report %s downloaded: SessionResultsPresentation_fac1_dep1_2010_100_'
+            'report %s downloaded: SessionResultsPresentation_fac1_dep1_CERT1_2010_100_'
             % job_id in logcontent
             )
@@ -192,5 +199,5 @@
                          'application/pdf')
         self.assertTrue(
-            'filename="SessionResultsPresentation_fac1_dep1_2010_0_' in
+            'filename="SessionResultsPresentation_fac1_dep1_CERT1_2010_0_' in
             self.browser.headers['content-disposition'])
         self.assertEqual(len(self.app['reports'].running_report_jobs), 1)
@@ -206,10 +213,11 @@
         self.assertTrue(
             'INFO - zope.mgr - students.reports.session_results_presentation.SessionResultsPresentationGeneratorPage - '
-            'report %s created: Session Results Presentation (faculty=fac1, department=dep1, session=2010, level=0)'
+            'report %s created: Session Results Presentation '
+            '(faculty=fac1, department=dep1, certificate=CERT1, session=2010, level=0)'
             % job_id in logcontent
             )
         self.assertTrue(
             'INFO - zope.mgr - students.reports.session_results_presentation.SessionResultsPresentationPDFView - '
-            'report %s downloaded: SessionResultsPresentation_fac1_dep1_2010_0_'
+            'report %s downloaded: SessionResultsPresentation_fac1_dep1_CERT1_2010_0_'
             % job_id in logcontent
             )
