Index: main/waeup.custom/trunk/src/waeup/custom/applicants/applicant.py
===================================================================
--- main/waeup.custom/trunk/src/waeup/custom/applicants/applicant.py	(revision 7865)
+++ main/waeup.custom/trunk/src/waeup/custom/applicants/applicant.py	(revision 7866)
@@ -19,10 +19,9 @@
 import grok
 from zope.interface import implementedBy
-from waeup.kofa.applicants.interfaces import IApplicantEdit
 from waeup.kofa.applicants.applicant import Applicant, ApplicantFactory
-from waeup.custom.applicants.interfaces import IPGApplicant
+from waeup.custom.applicants.interfaces import IPGApplicant, IPGApplicantEdit
 
 class PGApplicant(Applicant):
-    grok.implements(IPGApplicant,IApplicantEdit)
+    grok.implements(IPGApplicant,IPGApplicantEdit)
     grok.provides(IPGApplicant)
 
Index: main/waeup.custom/trunk/src/waeup/custom/applicants/interfaces.py
===================================================================
--- main/waeup.custom/trunk/src/waeup/custom/applicants/interfaces.py	(revision 7865)
+++ main/waeup.custom/trunk/src/waeup/custom/applicants/interfaces.py	(revision 7866)
@@ -19,5 +19,5 @@
 """
 
-from waeup.kofa.applicants.interfaces import IApplicant
+from waeup.kofa.applicants.interfaces import IApplicant, IApplicantEdit
 
 class IPGApplicant(IApplicant):
@@ -25,2 +25,14 @@
 
     """
+
+class IPGApplicantEdit(IApplicantEdit):
+    """A postgraduate applicant interface for editing.
+
+    Here we can repeat the fields from base data and set the
+    `required` and `readonly` attributes to True to further restrict
+    the data access. Or we can allow only certain certificates to be
+    selected by choosing the appropriate source.
+
+    We cannot omit fields here. This has to be done in the
+    respective form page.
+    """
Index: main/waeup.custom/trunk/src/waeup/custom/applicants/sample_applicant_data.csv
===================================================================
--- main/waeup.custom/trunk/src/waeup/custom/applicants/sample_applicant_data.csv	(revision 7866)
+++ main/waeup.custom/trunk/src/waeup/custom/applicants/sample_applicant_data.csv	(revision 7866)
@@ -0,0 +1,4 @@
+container_code,reg_number,firstname,lastname,date_of_birth,email,course1
+pg2011,1001,Aaren,Pieri,1990-01-02,xx@yy.zz,CERT1
+pg2011,1002,Aaren,Finau,1990-01-03,xx@yy.zz,CERT1
+pg2011,1003,Aaren,Berson,1990-01-04,xx@yy.zz,CERT1
Index: main/waeup.custom/trunk/src/waeup/custom/applicants/tests.py
===================================================================
--- main/waeup.custom/trunk/src/waeup/custom/applicants/tests.py	(revision 7866)
+++ main/waeup.custom/trunk/src/waeup/custom/applicants/tests.py	(revision 7866)
@@ -0,0 +1,131 @@
+## $Id$
+##
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import os
+import shutil
+import tempfile
+from zope.interface.verify import verifyClass, verifyObject
+from zope.component.hooks import setSite, clearSite
+from zope.component import createObject
+from waeup.kofa.app import University
+from waeup.kofa.university.faculty import Faculty
+from waeup.kofa.university.department import Department
+from waeup.kofa.testing import FunctionalTestCase
+from waeup.custom.testing import FunctionalLayer
+from waeup.kofa.interfaces import IBatchProcessor
+from waeup.kofa.applicants.applicant import Applicant
+from waeup.custom.applicants.container import PGApplicantsContainer
+from waeup.custom.applicants.applicant import PGApplicant
+from waeup.custom.applicants.batching import PGApplicantImporter
+from waeup.custom.applicants.interfaces import IPGApplicant, IPGApplicantEdit
+
+APPLICANT_SAMPLE_DATA = open(
+    os.path.join(os.path.dirname(__file__), 'sample_applicant_data.csv'),
+    'rb').read()
+APPLICANT_HEADER_FIELDS = APPLICANT_SAMPLE_DATA.split(
+    '\n')[0].split(',')
+
+class PGApplicantImporterTest(FunctionalTestCase):
+    """Perform some batching tests.
+    """
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(PGApplicantImporterTest, self).setUp()
+        # Setup a sample site for each test
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        # Prepopulate the ZODB...
+        self.getRootFolder()['app'] = app
+        # we add the site immediately after creation to the
+        # ZODB. Catalogs and other local utilities are not setup
+        # before that step.
+        self.app = self.getRootFolder()['app']
+        # Set site here. Some of the following setup code might need
+        # to access grok.getSite() and should get our new app then
+        setSite(app)
+
+        # Add an applicants container
+        self.container = PGApplicantsContainer()
+        self.container.code = u'pg2011'
+        self.app['applicants']['pg2011'] = self.container
+
+        # Populate university
+        self.certificate = createObject('waeup.Certificate')
+        self.certificate.code = 'CERT1'
+        self.certificate.application_category = 'basic'
+        self.certificate.start_level = 100
+        self.certificate.end_level = 500
+        self.app['faculties']['fac1'] = Faculty()
+        self.app['faculties']['fac1']['dep1'] = Department()
+        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
+            self.certificate)
+
+        # Add applicant with subobjects
+        applicant = PGApplicant()
+        applicant.firstname = u'Anna'
+        applicant.lastname = u'Tester'
+        self.app['applicants']['pg2011'].addApplicant(applicant)
+        self.application_number = applicant.application_number
+        self.applicant = self.app['applicants']['pg2011'][
+            self.application_number]
+        self.importer = PGApplicantImporter()
+        self.workdir = tempfile.mkdtemp()
+        self.csv_file = os.path.join(self.workdir, 'sample_applicant_data.csv')
+        open(self.csv_file, 'wb').write(APPLICANT_SAMPLE_DATA)
+
+    def tearDown(self):
+        super(PGApplicantImporterTest, self).tearDown()
+        shutil.rmtree(self.workdir)
+        shutil.rmtree(self.dc_root)
+        clearSite()
+        return
+
+    def test_interfaces(self):
+        # Make sure we fulfill the interface contracts.
+        assert verifyObject(IBatchProcessor, self.importer) is True
+        assert verifyClass(
+            IBatchProcessor, PGApplicantImporter) is True
+        assert verifyObject(IPGApplicant, self.applicant) is True
+        assert verifyClass(
+            IPGApplicant, PGApplicant) is True
+        assert verifyObject(IPGApplicantEdit, self.applicant) is True
+        assert verifyClass(
+            IPGApplicantEdit, PGApplicant) is True
+
+    def test_wrong_child(self):
+        applicant = Applicant()
+        applicant.firstname = u'Klaus'
+        applicant.lastname = u'Tester'
+        self.assertRaises(
+            TypeError, self.app['applicants']['pg2011'].addApplicant, applicant)
+
+    def test_import(self):
+        num, num_warns, fin_file, fail_file = self.importer.doImport(
+            self.csv_file, APPLICANT_HEADER_FIELDS)
+        self.assertEqual(num_warns,0)
+        keys = self.app['applicants']['pg2011'].keys()
+        assert len(keys) == 4
+        container = self.app['applicants']['pg2011']
+        assert  container.__implemented__.__name__ == (
+            'waeup.custom.applicants.container.PGApplicantsContainer')
+        applicant = container[keys[0]]
+        assert applicant.__implemented__.__name__ == (
+            'waeup.custom.applicants.applicant.PGApplicant')
+        shutil.rmtree(os.path.dirname(fin_file))
