Index: main/waeup.sirp/trunk/src/waeup/sirp/university/export.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/university/export.py	(revision 7752)
+++ main/waeup.sirp/trunk/src/waeup/sirp/university/export.py	(revision 7753)
@@ -139,7 +139,8 @@
                 value = None
         elif name == 'department_code':
-            value = getattr(
-                getattr(context, '__parent__', None),
-                'code', None)
+            try:
+                value = context.__parent__.__parent__.code
+            except AttributeError:
+                value = None
         return super(CourseExporter, self).mangle_value(
             value, name, context)
@@ -157,2 +158,25 @@
                     self.write_item(course, writer)
         return self.close_outfile(filepath, outfile)
+
+class CertificateExporter(CourseExporter, grok.GlobalUtility):
+    """Exporter for courses.
+    """
+    grok.implements(ICSVExporter)
+    grok.name('certificates')
+
+    #: Fieldnames considered by this exporter
+    fields = ('code', 'faculty_code', 'department_code', 'title', 'study_mode',
+              'start_level', 'end_level', 'application_category')
+
+    def export_all(self, site, filepath=None):
+        """Export faculties in facultycontainer into filepath as CSV data.
+
+        If `filepath` is ``None``, a raw string with CSV data is returned.
+        """
+        writer, outfile = self.get_csv_writer(filepath)
+        faculties = site.get('faculties', {})
+        for faculty in faculties.values():
+            for department in faculty.values():
+                for cert in department.certificates.values():
+                    self.write_item(cert, writer)
+        return self.close_outfile(filepath, outfile)
Index: main/waeup.sirp/trunk/src/waeup/sirp/university/tests/test_export.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/university/tests/test_export.py	(revision 7752)
+++ main/waeup.sirp/trunk/src/waeup/sirp/university/tests/test_export.py	(revision 7753)
@@ -8,8 +8,9 @@
 from waeup.sirp.testing import SIRPUnitTestLayer
 from waeup.sirp.university import (
-    FacultiesContainer, Faculty, Department, Course,
+    FacultiesContainer, Faculty, Department, Course, Certificate,
     )
 from waeup.sirp.university.export import (
     FacultyExporter, DepartmentExporter, CourseExporter,
+    CertificateExporter,
     )
 
@@ -213,7 +214,7 @@
         self.course2 = Course('Advanced Cheese Making', 'C2')
         self.course3 = Course('Selling Cheese', 'C3')
-        self.dept1.courses[u'C1'] = self.course1
-        self.dept1.courses['C2'] = self.course2
-        self.dept2.courses[u'C3'] = self.course3
+        self.dept1.courses.addCourse(self.course1)
+        self.dept1.courses.addCourse(self.course2)
+        self.dept2.courses.addCourse(self.course3)
         return
 
@@ -243,5 +244,5 @@
             result,
             'code,faculty_code,department_code,title,credits,passmark,semester\r\n'
-            'C1,F1,,Cheese Basics,0,40,1\r\n'
+            'C1,F1,D1,Cheese Basics,0,40,1\r\n'
             )
         return
@@ -254,6 +255,6 @@
             result,
             'code,faculty_code,department_code,title,credits,passmark,semester\r\n'
-            'C1,F1,,Cheese Basics,0,40,1\r\n'
-            'C2,F1,,Advanced Cheese Making,0,40,1\r\n'
+            'C1,F1,D1,Cheese Basics,0,40,1\r\n'
+            'C2,F1,D1,Advanced Cheese Making,0,40,1\r\n'
             )
         return
@@ -267,7 +268,7 @@
             result,
             'code,faculty_code,department_code,title,credits,passmark,semester\r\n'
-            'C1,F1,,Cheese Basics,0,40,1\r\n'
-            'C2,F1,,Advanced Cheese Making,0,40,1\r\n'
-            'C3,F1,,Selling Cheese,0,40,1\r\n'
+            'C1,F1,D1,Cheese Basics,0,40,1\r\n'
+            'C2,F1,D1,Advanced Cheese Making,0,40,1\r\n'
+            'C3,F1,D2,Selling Cheese,0,40,1\r\n'
             )
         return
@@ -280,7 +281,112 @@
             result,
             'code,faculty_code,department_code,title,credits,passmark,semester\r\n'
-            'C1,F1,,Cheese Basics,0,40,1\r\n'
-            'C2,F1,,Advanced Cheese Making,0,40,1\r\n'
-            'C3,F1,,Selling Cheese,0,40,1\r\n'
-            )
-        return
+            'C1,F1,D1,Cheese Basics,0,40,1\r\n'
+            'C2,F1,D1,Advanced Cheese Making,0,40,1\r\n'
+            'C3,F1,D2,Selling Cheese,0,40,1\r\n'
+            )
+        return
+
+class CertificateExporterTest(unittest.TestCase):
+    # Tests for CertificateExporter
+
+    layer = SIRPUnitTestLayer
+
+    def setUp(self):
+        self.workdir = tempfile.mkdtemp()
+        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
+        # create some departments and courses in a fake site
+        container = FacultiesContainer()
+        self.site = {'faculties':container}
+        self.fac = Faculty('Faculty of Cheese', 'faculty', 'F1')
+        container.addFaculty(self.fac)
+        self.dept1 = Department('Department of Cheddar', 'department', 'D1')
+        self.dept2 = Department('Institue of Gouda', 'institute', 'D2')
+        self.fac.addDepartment(self.dept1)
+        self.fac.addDepartment(self.dept2)
+        self.course1 = Course('Cheese Basics', 'C1')
+        self.course2 = Course('Advanced Cheese Making', 'C2')
+        self.course3 = Course('Selling Cheese', 'C3')
+        self.dept1.courses.addCourse(self.course1)
+        self.dept1.courses.addCourse(self.course2)
+        self.dept2.courses.addCourse(self.course3)
+        self.cert1 = Certificate(
+            'CERT1', 'Master of Cheese', study_mode=u'ct_ft', start_level=100,
+            end_level=300, application_category='basic')
+        self.cert2 = Certificate(
+            'CERT2', 'Master of Cheddar', study_mode='ct_ft', start_level=400,
+            end_level=700, application_category='cest')
+        self.cert3 = Certificate(
+            'CERT3', 'Cert. of Rubbish', study_mode='dp_pt', start_level=100,
+            end_level=200, application_category='no')
+        self.dept1.certificates.addCertificate(self.cert1)
+        self.dept1.certificates.addCertificate(self.cert2)
+        self.dept2.certificates.addCertificate(self.cert3)
+        return
+
+    def tearDown(self):
+        shutil.rmtree(self.workdir)
+        return
+
+    def test_ifaces(self):
+        # make sure we fullfill interface contracts
+        obj = CertificateExporter()
+        verifyObject(ICSVExporter, obj)
+        verifyClass(ICSVExporter, CertificateExporter)
+        return
+
+    def test_get_as_utility(self):
+        # we can get a certificate exporter as utility
+        result = queryUtility(ICSVExporter, name="certificates")
+        self.assertTrue(result is not None)
+        return
+
+    def test_export(self):
+        # we can export an iterable of certificates
+        exporter = CertificateExporter()
+        exporter.export([self.cert1], self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category\r\n'
+            'CERT1,F1,D1,Master of Cheese,ct_ft,100,300,basic\r\n'
+            )
+        return
+
+    def test_export_to_string(self):
+        # we can export an iterable of certificates to a string.
+        exporter = CertificateExporter()
+        result = exporter.export([self.cert1, self.cert2], filepath=None)
+        self.assertEqual(
+            result,
+            'code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category\r\n'
+            'CERT1,F1,D1,Master of Cheese,ct_ft,100,300,basic\r\n'
+            'CERT2,F1,D1,Master of Cheddar,ct_ft,400,700,cest\r\n'
+            )
+        return
+
+    def test_export_all(self):
+        # we can export all certificates in a site
+        exporter = CertificateExporter()
+        exporter.export_all(self.site, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(
+            result,
+            'code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category\r\n'
+            'CERT1,F1,D1,Master of Cheese,ct_ft,100,300,basic\r\n'
+            'CERT2,F1,D1,Master of Cheddar,ct_ft,400,700,cest\r\n'
+            'CERT3,F1,D2,Cert. of Rubbish,dp_pt,100,200,no\r\n'
+            )
+        return
+
+    def test_export_all_to_string(self):
+        # we can export all certificates in a site to a string
+        exporter = CertificateExporter()
+        result = exporter.export_all(self.site, filepath=None)
+        self.assertEqual(
+            result,
+            'code,faculty_code,department_code,title,study_mode,start_level,end_level,application_category\r\n'
+            'CERT1,F1,D1,Master of Cheese,ct_ft,100,300,basic\r\n'
+            'CERT2,F1,D1,Master of Cheddar,ct_ft,400,700,cest\r\n'
+            'CERT3,F1,D2,Cert. of Rubbish,dp_pt,100,200,no\r\n'
+            )
+        return
