Index: waeup/branches/ulif-importers/src/waeup/utils/batching.py
===================================================================
--- waeup/branches/ulif-importers/src/waeup/utils/batching.py	(revision 4828)
+++ waeup/branches/ulif-importers/src/waeup/utils/batching.py	(revision 4829)
@@ -14,5 +14,6 @@
 from zope.schema.interfaces import IText
 from waeup.interfaces import (IImporter, IFacultyContainer, IFaculty, ICourse,
-                              IDepartment, ISchemaTypeConverter, FatalCSVError)
+                              IDepartment, ICertificate, ISchemaTypeConverter,
+                              FatalCSVError)
 
 class BatchProcessor(grok.GlobalUtility):
@@ -46,7 +47,18 @@
     @property
     def required_fields(self):
+        """Required fields that have no default.
+
+        A list of names of field, whose value cannot be set if not
+        given during creation. Therefore these fields must exist in
+        input.
+
+        Fields with a default != missing_value do not belong to this
+        category.
+        """
         result = []
         for key, field in getFields(self.iface).items():
             if key in self.location_fields:
+                continue
+            if field.default is not field.missing_value:
                 continue
             if field.required:
@@ -162,7 +174,7 @@
 
     def updateEntry(self, obj, row, site):
-        """Update entry given by ``row`` with data delivered therein.
-        """
-        raise NotImplementedError('method not implemented')
+        for key, value in row.items():
+            setattr(obj, key, value)
+        return
 
     def createLogfile(self, path, fail_path, num, warnings, mode, user):
@@ -252,4 +264,6 @@
 
 class FacultyImporter(BatchProcessor):
+    """A batch processor for IFaculty objects.
+    """
     grok.provides(IImporter)
     grok.context(Interface)
@@ -288,10 +302,7 @@
         pass
 
-    def updateEntry(self, obj, row, site):
-        for key, value in row.items():
-            setattr(obj, key, value)
-        pass
-
 class DepartmentImporter(BatchProcessor):
+    """A batch processor for IDepartment objects.
+    """
     grok.provides(IImporter)
     grok.context(Interface)
@@ -335,10 +346,7 @@
         return
 
-    def updateEntry(self, obj, row, site):
-        for key, value in row.items():
-            setattr(obj, key, value)
-        return
-
 class CourseImporter(BatchProcessor):
+    """A batch processor for ICourse objects.
+    """
     grok.provides(IImporter)
     grok.context(Interface)
@@ -386,7 +394,49 @@
         return
 
-    def updateEntry(self, obj, row, site):
-        for key, value in row.items():
-            setattr(obj, key, value)
-        return
-
+class CertificateImporter(BatchProcessor):
+    """A batch processor for ICertificate objects.
+    """
+    grok.provides(IImporter)
+    grok.context(Interface)
+    util_name = 'certificateimporter'
+    grok.name(util_name)
+
+    name = u'Certificate importer'
+    iface = ICertificate
+
+    location_fields = ['code', 'faculty_code', 'department_code']
+    factory_name = 'waeup.Certificate'
+
+    def parentsExist(self, row, site):
+        if not 'faculties' in site.keys():
+            return False
+        if not row['faculty_code'] in site['faculties'].keys():
+            return False
+        faculty = site['faculties'][row['faculty_code']]
+        return row['department_code'] in faculty.keys()
+
+    def entryExists(self, row, site):
+        if not self.parentsExist(row, site):
+            return False
+        parent = self.getParent(row, site)
+        return row['code'] in parent.keys()
+
+    def getParent(self, row, site):
+        dept = site['faculties'][row['faculty_code']][row['department_code']]
+        return dept.certificates
+
+    def getEntry(self, row, site):
+        if not self.entryExists(row, site):
+            return None
+        parent = self.getParent(row, site)
+        return parent.get(row['code'])
+
+    def addEntry(self, obj, row, site):
+        parent = self.getParent(row, site)
+        parent.addCertificate(obj)
+        return
+
+    def delEntry(self, row, site):
+        parent = self.getParent(row, site)
+        del parent[row['code']]
+        return
