Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/batching.py	(revision 8290)
@@ -23,10 +23,14 @@
 from zope.interface import Interface
 from zope.component import queryUtility
+from hurry.workflow.interfaces import IWorkflowState
 from zope.catalog.interfaces import ICatalog
 from waeup.kofa.interfaces import (
-    IBatchProcessor, IObjectConverter, FatalCSVError, IGNORE_MARKER)
+    IBatchProcessor, IObjectConverter, FatalCSVError, IGNORE_MARKER,
+    IObjectHistory, IUserAccount)
+from waeup.kofa.interfaces import MessageFactory as _
 from waeup.kofa.utils.batching import BatchProcessor
 from waeup.kofa.applicants.interfaces import (
     IApplicantsContainer, IApplicant, IApplicantUpdateByRegNo)
+from waeup.kofa.applicants.workflow import  IMPORTABLE_STATES
 
 class ApplicantsContainerProcessor(BatchProcessor):
@@ -89,5 +93,6 @@
     def available_fields(self):
         return sorted(list(set(
-            ['application_number','reg_number','container_code'] + getFields(
+            ['application_number','reg_number',
+            'container_code','state','password'] + getFields(
                 self.iface).keys())))
 
@@ -150,4 +155,11 @@
         parent = self.getParent(row, site)
         parent.addApplicant(obj)
+        # We have to log this if state is provided. If not,
+        # logging is done by the event handler handle_applicant_added
+        if row.has_key('state'):
+            parent.__parent__.logger.info(
+            '%s - Application initialized' % obj.applicant_id)
+        history = IObjectHistory(obj)
+        history.addMessage(_('Application initialized'))
         return
 
@@ -158,4 +170,53 @@
             del parent[applicant.application_number]
         pass
+
+    def updateEntry(self, obj, row, site):
+        """Update obj to the values given in row.
+        """
+        items_changed = ''
+
+        # Remove application_number from row if empty
+        if row.has_key('application_number') and row['application_number'] in (
+            None, IGNORE_MARKER):
+            row.pop('application_number')
+
+        # Update applicant_id fom application_number and container code
+        # if application_number is given
+        if row.has_key('application_number'):
+            obj.applicant_id = u'%s_%s' % (
+                row['container_code'], row['application_number'])
+            row.pop('application_number')
+
+        # Update password
+        passwd = row.get('password', IGNORE_MARKER)
+        if passwd not in ('', IGNORE_MARKER):
+            IUserAccount(obj).setPassword(passwd)
+            row.pop('password')
+
+        # Update registration state
+        state = row.get('state', IGNORE_MARKER)
+        if state not in (IGNORE_MARKER, ''):
+            value = row['state']
+            IWorkflowState(obj).setState(value)
+            msg = _("State '${a}' set", mapping = {'a':value})
+            history = IObjectHistory(obj)
+            history.addMessage(msg)
+            row.pop('state')
+
+        # apply other values...
+        items_changed = super(ApplicantProcessor, self).updateEntry(
+            obj, row, site)
+
+        # Log actions...
+        parent = self.getParent(row, site)
+        if hasattr(obj,'application_number'):
+            # Update mode: the applicant exists and we can get the applicant_id
+            parent.__parent__.logger.info(
+                '%s - Application record updated: %s'
+                % (obj.applicant_id, items_changed))
+        else:
+            # Create mode: the applicant does not yet exist
+            parent.logger.info('Application record imported: %s' % items_changed)
+        return items_changed
 
     def getMapping(self, path, headerfields, mode):
@@ -186,3 +247,14 @@
         errs, inv_errs, conv_dict =  converter.fromStringDict(
             row, self.factory_name, mode=mode)
+        if row.has_key('state') and \
+            not row['state'] in IMPORTABLE_STATES:
+            if row['state'] not in (IGNORE_MARKER, ''):
+                errs.append(('state','not allowed'))
+            else:
+                # state is an attribute of Applicant and must not
+                # be changed if empty
+                conv_dict['state'] = IGNORE_MARKER
+        application_number = row.get('application_number', IGNORE_MARKER)
+        if application_number in (IGNORE_MARKER, ''):
+                conv_dict['application_number'] = IGNORE_MARKER
         return errs, inv_errs, conv_dict
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/container.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/container.py	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/container.py	(revision 8290)
@@ -89,6 +89,7 @@
             raise TypeError(
                 'ApplicantsContainers contain only IApplicant instances')
-        applicant_id = generate_applicant_id(container=self)
-        applicant.applicant_id = applicant_id
+        if applicant.applicant_id is None:
+            applicant_id = generate_applicant_id(container=self)
+            applicant.applicant_id = applicant_id
         self[applicant.application_number] = applicant
         return
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data.csv
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data.csv	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data.csv	(revision 8290)
@@ -1,4 +1,4 @@
-container_code,reg_number,firstname,lastname,date_of_birth,email,course1,sex,middlename
-dp2011,1001,Aaren,Pieri,1990-01-02,xx@yy.zz,CERT1,m,Peter
-dp2011,1002,Aaren,Finau,1990-01-03,xx@yy.zz,CERT1,m,Claus
-dp2011,1003,Aaren,Berson,1990-01-04,xx@yy.zz,CERT1,m,Alfons
+application_number,container_code,reg_number,firstname,lastname,date_of_birth,email,course1,sex,middlename
+1234,dp2011,1001,Aaren,Pieri,1990-01-02,xx@yy.zz,CERT1,m,Peter
+2345,dp2011,1002,Aaren,Finau,1990-01-03,xx@yy.zz,CERT1,m,Claus
+,dp2011,1003,Aaren,Berson,1990-01-04,xx@yy.zz,CERT1,m,Alfons
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data_update.csv
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data_update.csv	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data_update.csv	(revision 8290)
@@ -1,4 +1,4 @@
-container_code,reg_number,firstname,middlename
-dp2011,1001,Aaren,
-dp2011,1002,Alfons,
-dp2011,1003,Abraham,
+container_code,reg_number,firstname,middlename,state
+dp2011,1001,Aaren,,
+dp2011,1002,Alfons,,admitted
+dp2011,1003,Abraham,,
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data_update2.csv
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data_update2.csv	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_applicant_data_update2.csv	(revision 8290)
@@ -1,4 +1,4 @@
-container_code,reg_number,firstname,middlename
-dp2011,1001,Aaren,XXX
-dp2011,1002,Alfons,XXX
-dp2011,1003,Abraham,XXX
+container_code,reg_number,firstname,middlename,application_number
+dp2011,1001,Aaren,XXX,
+dp2011,1002,Alfons,XXX,
+dp2011,1003,Abraham,XXX,
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_faulty_applicant_data.csv
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_faulty_applicant_data.csv	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/sample_faulty_applicant_data.csv	(revision 8290)
@@ -1,2 +1,2 @@
-container_code,reg_number,firstname,lastname,date_of_birth,email,course1,sex,middlename
-dp2011,1001,Aaren,Pieri,01/02/1990,xx@yy.zz,CERT1,m,Claus
+application_number,container_code,reg_number,firstname,lastname,date_of_birth,email,course1,sex,middlename
+,dp2011,1001,Aaren,Pieri,01/02/1990,xx@yy.zz,CERT1,m,Claus
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_batching.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_batching.py	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_batching.py	(revision 8290)
@@ -311,4 +311,5 @@
         num, num_warns, fin_file, fail_file = self.processor.doImport(
             self.csv_file_update, APPLICANT_HEADER_FIELDS_UPDATE, 'update')
+        #content = open(fail_file).read()
         self.assertEqual(num_warns,0)
         # The middlename import value was None.
@@ -320,4 +321,8 @@
                 break
         self.assertEqual(applicant.middlename, 'Peter')
+        # state of Pieri has not changed
+        self.assertEqual(container['1234'].state,'initialized')
+        # state of Finau has changed
+        self.assertEqual(container['2345'].state,'admitted')
         shutil.rmtree(os.path.dirname(fin_file))
         # Now we import another file which clears all middlename attributes.
Index: main/waeup.kofa/trunk/src/waeup/kofa/applicants/workflow.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/applicants/workflow.py	(revision 8289)
+++ main/waeup.kofa/trunk/src/waeup/kofa/applicants/workflow.py	(revision 8290)
@@ -33,4 +33,6 @@
 NOT_ADMITTED = 'not admitted'
 CREATED = 'created'
+
+IMPORTABLE_STATES = (INITIALIZED, PAID, SUBMITTED, ADMITTED, NOT_ADMITTED)
 
 application_states_dict = {
