Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/viewlets.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/viewlets.py	(revision 9841)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/viewlets.py	(revision 9842)
@@ -472,11 +472,4 @@
     text = _('Edit course')
     
-class ManageCertificateActionButton(ManageActionButton):
-    """ 'Manage settings' button for certificates.
-    """
-    grok.context(ICertificate)
-    grok.view(CertificatePage)
-    text = _('Manage certificate')
-
 class ShowCourseStudentsActionButton(ManageActionButton):
     """ 'Show students' button in course.
@@ -489,4 +482,12 @@
     target = 'students'
 
+class ManageCertificateActionButton(ManageActionButton):
+    """ 'Manage settings' button for certificates.
+    """
+    grok.context(ICertificate)
+    grok.view(CertificatePage)
+    text = _('Manage certificate')
+    grok.order(1)
+
 class ShowCertificateStudentsActionButton(ManageActionButton):
     """ 'Show students' button for certificates.
@@ -498,4 +499,16 @@
     text = _('Show students')
     target = 'students'
+    grok.order(2)
+
+class ExportCertificateStudentsActionButton(ManageActionButton):
+    """ 'Export student data' button for certificates.
+    """
+    grok.context(ICertificate)
+    grok.view(CertificatePage)
+    grok.require('waeup.showStudents')
+    icon = 'actionicon_down.png'
+    text = _('Export student data')
+    target = 'exports'
+    grok.order(3)
 
 class ManageCertificateCourseActionButton(ManageActionButton):
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 9841)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 9842)
@@ -56,4 +56,6 @@
 from waeup.kofa.university.department import (
     VirtualDepartmentExportJobContainer,)
+from waeup.kofa.university.certificate import (
+    VirtualCertificateExportJobContainer,)
 from waeup.kofa.university.vocabularies import course_levels
 from waeup.kofa.utils.batching import VirtualExportJobContainer
@@ -2724,4 +2726,8 @@
         return None
 
+    @property
+    def certcode(self):
+        return None
+
     def update(self, START=None, session=None, level=None, mode=None,
                exporter=None):
@@ -2743,9 +2749,11 @@
                                       current_level=level,
                                       current_mode=mode,
-                                      depcode=self.depcode)
+                                      depcode=self.depcode,
+                                      certcode=self.certcode)
         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
         self.context.logger.info(
-            '%s - exported: %s (%s, %s, %s, %s), job_id=%s'
-            % (ob_class, exporter, session, level, mode, self.depcode, job_id))
+            '%s - exported: %s (%s, %s, %s, %s, %s), job_id=%s'
+            % (ob_class, exporter, session, level, mode, self.depcode,
+            self.certcode, job_id))
         self.flash(_('Export started for students with') +
                    ' current_session=%s, current_level=%s, study_mode=%s' % (
@@ -2777,2 +2785,12 @@
     def depcode(self):
         return self.context.__parent__.code
+
+class CertificateExportJobContainerJobConfig(ExportJobContainerJobConfig):
+    """Page that configures a students export job for certificates.
+
+    """
+    grok.context(VirtualCertificateExportJobContainer)
+
+    @property
+    def certcode(self):
+        return self.context.__parent__.code
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 9841)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 9842)
@@ -2776,13 +2776,61 @@
         self.assertTrue(
             'zope.mgr - students.browser.DepartmentExportJobContainerJobConfig '
-            '- exported: students (2004, 100, ug_ft, dep1), job_id='
+            '- exported: students (2004, 100, ug_ft, dep1, None), job_id=%s'
+            % job_id in logcontent
             )
         self.assertTrue(
             'zope.mgr - students.browser.ExportJobContainerDownload '
             '- downloaded: WAeUP.Kofa_students_%s.csv, job_id=%s'
-            % (job_id, job_id)
+            % (job_id, job_id) in logcontent
             )
         self.assertTrue(
             'zope.mgr - students.browser.ExportJobContainerOverview '
-            '- discarded: job_id=%s' % job_id
+            '- discarded: job_id=%s' % job_id in logcontent
             )
+
+    def test_certificate_export(self):
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        cert1_path = 'http://localhost/app/faculties/fac1/dep1/certificates/CERT1'
+        self.browser.open(cert1_path)
+        self.browser.getLink("Export student data").click()
+        self.browser.getControl("Configure new export").click()
+        self.browser.getControl(name="exporter").value = ['students']
+        self.browser.getControl(name="session").value = ['2004']
+        self.browser.getControl(name="level").value = ['100']
+        self.browser.getControl(name="mode").value = ['ug_ft']
+        self.browser.getControl("Create CSV file").click()
+
+        # When the job is finished and we reload the page...
+        job_id = self.wait_for_export_job_completed()
+        self.browser.open(cert1_path + '/exports')
+        # ... the csv file can be downloaded ...
+        self.browser.getLink("Download").click()
+        self.assertEqual(self.browser.headers['content-type'],
+            'text/csv; charset=UTF-8')
+        self.assertTrue(
+            'filename="WAeUP.Kofa_students_%s.csv' % job_id in
+            self.browser.headers['content-disposition'])
+        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
+        job_id = self.app['datacenter'].running_exports[0][0]
+        # ... and discarded
+        self.browser.open(cert1_path + '/exports')
+        self.browser.getControl("Discard").click()
+        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
+        # Creation, downloading and discarding is logged
+        logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'datacenter.log')
+        logcontent = open(logfile).read()
+        self.assertTrue(
+            'zope.mgr - students.browser.CertificateExportJobContainerJobConfig '
+            '- exported: students (2004, 100, ug_ft, None, CERT1), job_id=%s'
+            % job_id in logcontent
+            )
+        self.assertTrue(
+            'zope.mgr - students.browser.ExportJobContainerDownload '
+            '- downloaded: WAeUP.Kofa_students_%s.csv, job_id=%s'
+            % (job_id, job_id) in logcontent
+            )
+        self.assertTrue(
+            'zope.mgr - students.browser.ExportJobContainerOverview '
+            '- discarded: job_id=%s' % job_id in logcontent
+            )
Index: main/waeup.kofa/trunk/src/waeup/kofa/university/certificate.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/university/certificate.py	(revision 9841)
+++ main/waeup.kofa/trunk/src/waeup/kofa/university/certificate.py	(revision 9842)
@@ -19,4 +19,5 @@
 """
 import grok
+import zope.location.location
 from zope.event import notify
 from zope.catalog.interfaces import ICatalog
@@ -30,4 +31,9 @@
     ICertificate, ICertificateAdd, ICertificateCourse)
 from waeup.kofa.university.vocabularies import course_levels
+from waeup.kofa.utils.batching import VirtualExportJobContainer
+
+class VirtualCertificateExportJobContainer(VirtualExportJobContainer):
+    """A virtual export job container for certificates.
+    """
 
 class Certificate(grok.Container):
@@ -61,4 +67,14 @@
         self.school_fee_3 = school_fee_3
         self.school_fee_4 = school_fee_4
+
+    def traverse(self, name):
+        """Deliver appropriate containers.
+        """
+        if name == 'exports':
+            # create a virtual exports container and return it
+            container = VirtualCertificateExportJobContainer()
+            zope.location.location.located(container, self, 'exports')
+            return container
+        return None
 
     def longtitle(self):
