Index: main/waeup.ikoba/trunk/src/waeup/ikoba/app.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/app.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/app.py	(revision 12256)
@@ -42,6 +42,4 @@
     grok.implements(ICompany)
 
-    _curr_doc_id = 101
-
     _curr_con_id = 101
 
@@ -56,23 +54,4 @@
         self.setup()
         return
-
-    @property
-    def unique_document_id(self):
-        """A unique document id for all documents in company.
-
-        The document id returned is guaranteed to be unique. 
-
-        Once a document id was issued, it won't be issued again.
-
-        Obtaining a document id is currently not thread-safe but can be
-        made easily by enabling commented lines.
-        """
-        # lock.acquire() # lock data
-        new_id = u'd%s' % (self._curr_doc_id)
-        self._curr_doc_id += 1
-        # self._p_changed = True
-        # commit()
-        # lock.release() # end of lock
-        return new_id
 
     @property
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/batching.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/batching.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/batching.py	(revision 12256)
@@ -40,5 +40,4 @@
 from waeup.ikoba.interfaces import IIkobaUtils
 from waeup.ikoba.interfaces import MessageFactory as _
-from waeup.ikoba.documents.utils import generate_document_id
 from waeup.ikoba.customers.utils import generate_contract_id
 from waeup.ikoba.customers.interfaces import (
@@ -398,32 +397,40 @@
 
     def getEntry(self, row, site):
-        documents = self.getParent(row, site)
-        if documents is None:
-            return None
         document_id = row.get('document_id', None)
         if document_id is None:
             return None
-        entry = documents.get(document_id)
-        return entry
+        cat = queryUtility(ICatalog, name='documents_catalog')
+        results = list(cat.searchResults(document_id=(document_id, document_id)))
+        if results:
+            return results[0]
+        return None
+
+        #documents = self.getParent(row, site)
+        #if documents is None:
+        #    return None
+        #document_id = row.get('document_id', None)
+        #if document_id is None:
+        #    return None
+        #entry = documents.get(document_id)
+        #return entry
 
     def updateEntry(self, obj, row, site, filename):
         """Update obj to the values given in row.
         """
+        # Remove document_id from row if empty
+        if 'document_id' in row and row['document_id'] in (None, IGNORE_MARKER):
+            row.pop('document_id')
         items_changed = super(CustomerDocumentProcessor, self).updateEntry(
             obj, row, site, filename)
         customer = self.getParent(row, site).__parent__
         customer.__parent__.logger.info(
-            '%s - %s - %s - updated: %s'
-            % (self.name, filename, customer.customer_id, items_changed))
+            '%s - %s - %s - %s - updated: %s'
+            % (self.name, filename, customer.customer_id, obj.document_id,
+               items_changed))
         return
 
     def addEntry(self, obj, row, site):
         parent = self.getParent(row, site)
-        document_id = row['document_id'].strip('#')
-        parent[document_id] = obj
-        # Reset _curr_doc_id if document_id has been imported
-        site = grok.getSite()
-        if row.get('document_id', None) not in (None, IGNORE_MARKER):
-            site._curr_doc_id -= 1
+        parent.addDocument(obj)
         return
 
@@ -449,28 +456,4 @@
             if class_name != self.factory_name.strip('waeup.'):
                 errs.append(('class_name','wrong processor'))
-        try:
-            # Correct doc_id counter. As the IConverter for documents
-            # creates document objects that are not used afterwards, we
-            # have to fix the site-wide doc_id counter.
-            site = grok.getSite()
-            site._curr_doc_id -= 1
-        except (KeyError, TypeError, AttributeError):
-                pass
-        # We have to check document_id.
-        document_id = row.get('document_id', None)
-        if mode == 'create':
-            if not document_id:
-                document_id = generate_document_id()
-                conv_dict['document_id'] = document_id
-                return errs, inv_errs, conv_dict
-            cat = queryUtility(ICatalog, name='documents_catalog')
-            results = list(
-                cat.searchResults(document_id=(document_id, document_id)))
-            if results:
-                # document_id must not exist.
-                errs.append(('document_id','id exists'))
-        else:
-            if not document_id.startswith('d'):
-                errs.append(('document_id','invalid format'))
         return errs, inv_errs, conv_dict
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12256)
@@ -817,5 +817,5 @@
     pnav = 4
 
-    form_fields = grok.AutoFields(ICustomerDocument)
+    form_fields = grok.AutoFields(ICustomerDocument).omit('document_id')
 
     @property
@@ -876,5 +876,6 @@
     @property
     def form_fields(self):
-        return grok.AutoFields(self.context.form_fields_interface)
+        return grok.AutoFields(
+            self.context.form_fields_interface).omit('document_id')
 
     def update(self):
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py	(revision 12256)
@@ -33,5 +33,5 @@
 from waeup.ikoba.interfaces import (
     IFileStoreNameChooser, IFileStoreHandler,
-    IIkobaUtils, IExtFileStore)
+    IIkobaUtils, IExtFileStore, IIDSource)
 from waeup.ikoba.customers.interfaces import (
     ICustomerDocumentsContainer, ICustomerNavigation, ICustomerDocument,
@@ -76,4 +76,10 @@
     # tuple should contain only a single filename string.
     filenames = ()
+
+    def __init__(self):
+        super(CustomerDocumentBase, self).__init__()
+        source = getUtility(IIDSource)
+        self.document_id = unicode(source.get_hex_uuid())
+        return
 
     @property
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/sample_contract_data.csv
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/sample_contract_data.csv	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/sample_contract_data.csv	(revision 12256)
@@ -1,8 +1,8 @@
 class_name,contract_id,reg_number,title,product_object,document_object
-SampleContract,c3,1,My first contract,SAM,d101
-SampleContract,c4,2,My second contract,SAM,d101
-SampleContract,c5,3,My third contract,SAM,d101
-SampleContract,,1,My 4th contract,SAM,d101
-SampleContract,c5,2,My stolen contract,SAM,d101
+SampleContract,c3,1,My first contract,SAM,DOC1
+SampleContract,c4,2,My second contract,SAM,DOC1
+SampleContract,c5,3,My third contract,SAM,DOC1
+SampleContract,,1,My 4th contract,SAM,DOC1
+SampleContract,c5,2,My stolen contract,SAM,DOC1
 SampleContract,c6,3,My 5th contract,SAM,NONEXISTENT
-SampleContract,c7,3,My sixt contract,NONEXISTENT,d101
+SampleContract,c7,3,My sixt contract,NONEXISTENT,DOC1
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_batching.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_batching.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_batching.py	(revision 12256)
@@ -132,4 +132,5 @@
         document = createObject('waeup.CustomerSampleDocument')
         document.title = u'My Document'
+        document.document_id = u'DOC1'
         customer['documents'].addDocument(document)
         IWorkflowState(document).setState(VERIFIED)
@@ -151,5 +152,5 @@
         super(CustomerProcessorTest, self).setUp()
 
-        # Add customer with subobjects
+        # Add customer
         customer = Customer()
         self.app['customers'].addCustomer(customer)
@@ -305,25 +306,24 @@
             dict(customer_id='ID_NONE', document_id='nonsense'), self.app) is None
         assert self.processor.getEntry(
-            dict(customer_id=self.customer.customer_id, document_id='d101'),
-            self.app) is self.customer['documents']['d101']
+            dict(customer_id=self.customer.customer_id, document_id='DOC1'),
+            self.app) is self.customer['documents']['DOC1']
 
     def test_delEntry(self):
         assert self.processor.getEntry(
-            dict(customer_id=self.customer.customer_id, document_id='d101'),
-            self.app) is self.customer['documents']['d101']
+            dict(customer_id=self.customer.customer_id, document_id='DOC1'),
+            self.app) is self.customer['documents']['DOC1']
         self.assertEqual(len(self.customer['documents'].keys()),1)
         self.processor.delEntry(
-            dict(customer_id=self.customer.customer_id, document_id='d101'),
+            dict(customer_id=self.customer.customer_id, document_id='DOC1'),
             self.app)
         assert self.processor.getEntry(
-            dict(customer_id=self.customer.customer_id, document_id='d101'),
+            dict(customer_id=self.customer.customer_id, document_id='DOC1'),
             self.app) is None
         self.assertEqual(len(self.customer['documents'].keys()),0)
 
     def test_addEntry(self):
-        self.assertEqual(self.app._curr_doc_id, 102)
         self.assertEqual(len(self.customer['documents'].keys()),1)
         document1 = createObject(u'waeup.CustomerSampleDocument')
-        document1.document_id = 'd234'
+        document1.document_id = u'd234'
         self.processor.addEntry(
             document1, dict(customer_id=self.customer.customer_id, document_id='d234'),
@@ -331,34 +331,26 @@
         self.assertEqual(len(self.customer['documents'].keys()),2)
         self.assertEqual(self.customer['documents']['d234'].document_id, 'd234')
-        # _curr_doc_id hasn't changed
-        self.assertEqual(self.app._curr_doc_id, 102)
 
     def test_checkConversion(self):
-        self.assertEqual(self.app._curr_doc_id, 102)
-        errs, inv_errs, conv_dict = self.processor.checkConversion(
-            dict(document_id='d126', class_name='CustomerSampleDocument'))
+        errs, inv_errs, conv_dict = self.processor.checkConversion(
+            dict(document_id='DOC', class_name='CustomerSampleDocument'))
         self.assertEqual(len(errs),0)
-        errs, inv_errs, conv_dict = self.processor.checkConversion(
-            dict(document_id='nonsense', class_name='CustomerSampleDocument'))
+        #errs, inv_errs, conv_dict = self.processor.checkConversion(
+        #    dict(document_id='id with spaces', class_name='CustomerSampleDocument'))
+        #self.assertEqual(len(errs),1)
+        errs, inv_errs, conv_dict = self.processor.checkConversion(
+            dict(document_id='DOC', class_name='WrongDocument'))
         self.assertEqual(len(errs),1)
-        errs, inv_errs, conv_dict = self.processor.checkConversion(
-            dict(document_id='d127', class_name='WrongDocument'))
-        self.assertEqual(len(errs),1)
-        errs, inv_errs, conv_dict = self.processor.checkConversion(
-            dict(document_id='', class_name='CustomerSampleDocument',
-            mode='update'))
-        self.assertEqual(len(errs),1)
-        # _curr_doc_id hasn't changed
-        self.assertEqual(self.app._curr_doc_id, 102)
 
     def test_import(self):
         num, num_warns, fin_file, fail_file = self.processor.doImport(
             self.csv_file, DOCUMENT_HEADER_FIELDS,'create')
+        fail_file = open(fail_file).read()
         self.assertEqual(num_warns,1)
         # document_id must be unique
-        fail_file = open(fail_file).read()
         self.assertEqual(fail_file,
             'class_name,reg_number,document_id,title,--ERRORS--\r\n'
-            'CustomerSampleDocument,2,d5,My stolen doc,document_id: id exists\r\n')
+            'CustomerSampleDocument,2,d5,My stolen doc,'
+            'This object already exists. Skipping.\r\n')
         document = self.processor.getEntry(dict(reg_number='1',
             document_id='d3'), self.app)
@@ -371,10 +363,12 @@
         shutil.rmtree(os.path.dirname(fin_file))
         logcontent = open(self.logfile).read()
-        # Logging message from updateEntry
+        # Fetch uuid
+        docid = [i for i in self.app['customers']['X666666']['documents'].keys()
+            if len(i) > 10][0]
+         # Logging message from updateEntry
         self.assertTrue(
             'INFO - system - CustomerDocument Processor - '
-            'sample_document_data - X666666 - updated: '
-            'document_id=d3, title=My first doc'
-            in logcontent)
+            'sample_document_data - X666666 - %s - updated: title=My 4th doc'
+            % docid in logcontent)
 
     def test_import_update(self):
@@ -387,6 +381,6 @@
         num, num_warns, fin_file, fail_file = self.processor.doImport(
             self.csv_file, DOCUMENT_HEADER_FIELDS,'update')
-        # There is one record without document_id and one duplicate
-        self.assertEqual(num_warns,2)
+        # There is one record without document_id
+        self.assertEqual(num_warns,1)
         shutil.rmtree(os.path.dirname(fin_file))
 
@@ -475,5 +469,5 @@
         errs, inv_errs, conv_dict = self.processor.checkConversion(
             dict(contract_id='c126', class_name='SampleContract',
-                 document_object='d101', product_object='SAM'))
+                 document_object='DOC1', product_object='SAM'))
         self.assertEqual(len(errs),0)
         errs, inv_errs, conv_dict = self.processor.checkConversion(
@@ -495,9 +489,9 @@
             'reg_number,contract_id,title,class_name,product_object,'
             'document_object,--ERRORS--\r\n'
-            '2,c5,My stolen contract,SampleContract,SAM,d101,'
+            '2,c5,My stolen contract,SampleContract,SAM,DOC1,'
             'contract_id: id exists\r\n'
             '3,c6,My 5th contract,SampleContract,SAM,NONEXISTENT,'
             'document_object: Invalid value\r\n'
-            '3,c7,My sixt contract,SampleContract,NONEXISTENT,d101,'
+            '3,c7,My sixt contract,SampleContract,NONEXISTENT,DOC1,'
             'product_object: Invalid value\r\n')
         contract = self.processor.getEntry(dict(reg_number='1',
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12256)
@@ -120,4 +120,5 @@
         self.document = createObject('waeup.CustomerSampleDocument')
         self.document.title = u'My first document'
+        self.document.document_id = u'DOC1'
         self.customer['documents'].addDocument(self.document)
         self.contract = createObject('waeup.SampleContract')
@@ -834,8 +835,9 @@
         self.browser.getControl("Add document").click()
         self.assertTrue('PDF Document added.' in self.browser.contents)
-        document = self.customer['documents']['d102']
+        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
+        document = self.customer['documents'][docid]
 
         # Document can be edited
-        self.browser.getLink("d102").click()
+        self.browser.getLink(docid).click()
         self.browser.getLink("Manage").click()
         self.browser.getControl(name="form.title").value = 'My second doc'
@@ -843,5 +845,6 @@
         self.assertTrue('Form has been saved.' in self.browser.contents)
         self.browser.getLink("View").click()
-        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
+        self.assertEqual(self.browser.url,
+            self.documents_path + '/' + docid + '/index')
 
         # Transitions can be performed
@@ -859,9 +862,9 @@
 
         # Manage button and form is no longer available
-        self.browser.open(self.documents_path + '/d102/index')
+        self.browser.open(self.documents_path + '/' + docid + '/index')
         self.assertFalse(
-            'href="http://localhost/app/customers/K1000000/documents/d102/manage"'
-            in self.browser.contents)
-        self.browser.open(self.documents_path + '/d102/manage')
+            'href="http://localhost/app/customers/K1000000/documents/%s/manage"'
+            % docid in self.browser.contents)
+        self.browser.open(self.documents_path + '/' + docid + '/manage')
         self.assertTrue(
             'The requested form is locked (read-only)'
@@ -881,5 +884,5 @@
 
         self.assertTrue(
-            'INFO - system - K1000000 - d101 - Document created'
+            'INFO - system - K1000000 - DOC1 - Document created'
             in logcontent)
         self.assertTrue(
@@ -889,12 +892,12 @@
         self.assertTrue(
             'INFO - zope.mgr - customers.browser.DocumentManageFormPage '
-            '- K1000000 - d102 - saved: title'
+            '- K1000000 - %s - saved: title' % docid
             in logcontent)
         self.assertTrue(
-            'INFO - zope.mgr - K1000000 - d102 - Submitted for verification'
-            in logcontent)
+            'INFO - zope.mgr - K1000000 - %s - Submitted for verification'
+            % docid in logcontent)
         self.assertTrue(
             'INFO - zope.mgr - customers.browser.DocumentsManageFormPage '
-            '- K1000000 - removed: d102'
+            '- K1000000 - removed: %s' % docid
             in logcontent)
 
@@ -913,14 +916,15 @@
         self.browser.getControl("Add document").click()
         self.assertTrue('Sample Document added.' in self.browser.contents)
-        document = self.customer['documents']['d102']
+        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
+        document = self.customer['documents'][docid]
 
         # Document can be edited ...
-        self.browser.getLink("d102").click()
-        self.browser.open(self.documents_path + '/d102/edit')
+        self.browser.getLink(docid).click()
+        self.browser.open(self.documents_path + '/' + docid + '/edit')
         #self.browser.getLink("Edit").click()
         self.assertTrue('The requested form is locked' in self.browser.contents)
         # Customer is in wrong state
         IWorkflowState(self.customer).setState(APPROVED)
-        self.browser.open(self.documents_path + '/d102/edit')
+        self.browser.open(self.documents_path + '/' + docid + '/edit')
         self.browser.getControl(name="form.title").value = 'My second doc'
         self.browser.getControl("Save").click()
@@ -928,5 +932,6 @@
         self.assertTrue('Form has been saved.' in self.browser.contents)
         self.browser.getLink("View").click()
-        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
+        self.assertEqual(
+            self.browser.url, self.documents_path + '/%s/index' % docid)
         # Costumer can upload a document.
         self.browser.getLink("Edit").click()
@@ -938,6 +943,6 @@
             name='upload_samplescaneditupload').click()
         self.assertTrue(
-            'href="http://localhost/app/customers/K1000000/documents/d102/sample"'
-            in self.browser.contents)
+            'href="http://localhost/app/customers/K1000000/documents/%s/sample"'
+            % docid in self.browser.contents)
         # Costumer can submit the form. The form is also saved.
         self.browser.getControl(name="form.title").value = 'My third doc'
@@ -947,5 +952,5 @@
         self.assertTrue('Document State: submitted for verification' in self.browser.contents)
         # Customer can't edit the document once it has been submitted
-        self.browser.open(self.documents_path + '/d102/edit')
+        self.browser.open(self.documents_path + '/%s/edit' % docid)
         self.assertTrue('The requested form is locked' in self.browser.contents)
 
@@ -954,5 +959,5 @@
         # The image is stored even if form has errors
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-        self.browser.open(self.customer_path + '/documents/d101/manage')
+        self.browser.open(self.customer_path + '/documents/DOC1/manage')
         # Create a pseudo image file and select it to be uploaded 
         image = open(SAMPLE_IMAGE, 'rb')
@@ -963,5 +968,5 @@
         self.browser.getControl("Save").click() # submit form
         self.assertFalse(
-            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
+            'href="http://localhost/app/customers/K1000000/documents/DOC1/sample"'
             in self.browser.contents)
         # ... but the correct upload submit button does
@@ -973,5 +978,5 @@
             name='upload_samplescanmanageupload').click()
         self.assertTrue(
-            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
+            'href="http://localhost/app/customers/K1000000/documents/DOC1/sample"'
             in self.browser.contents)
         # Browsing the link shows a real image
@@ -981,5 +986,5 @@
         self.assertEqual(len(self.browser.contents), 2787)
         # We can't reupload a file. The existing file must be deleted first.
-        self.browser.open(self.customer_path + '/documents/d101/manage')
+        self.browser.open(self.customer_path + '/documents/DOC1/manage')
         self.assertFalse(
             'upload_samplescanmanageupload' in self.browser.contents)
@@ -1024,5 +1029,5 @@
     def test_verify_document(self):
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-        self.browser.open(self.customer_path + '/documents/d101/manage')
+        self.browser.open(self.customer_path + '/documents/DOC1/manage')
         image = open(SAMPLE_IMAGE, 'rb')
         ctrl = self.browser.getControl(name='samplescanmanageupload')
@@ -1035,5 +1040,5 @@
         self.assertEqual(
             getattr(self.document, 'sample_md5', None), None)
-        self.browser.open(self.documents_path + '/d101/trigtrans')
+        self.browser.open(self.documents_path + '/DOC1/trigtrans')
         self.browser.getControl(name="transition").value = ['verify']
         self.browser.getControl("Apply now").click()
@@ -1051,5 +1056,6 @@
         self.browser.getControl(name="form.title").value = 'My PDF Document'
         self.browser.getControl("Add document").click()
-        self.browser.open(self.documents_path + '/d102/manage')
+        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
+        self.browser.open(self.documents_path + '/%s/manage' % docid)
         # Create a pseudo image file and select it to be uploaded
         image = open(SAMPLE_IMAGE, 'rb')
@@ -1075,6 +1081,6 @@
             name='upload_pdfscanmanageupload').click()
         self.assertTrue(
-            'href="http://localhost/app/customers/K1000000/documents/d102/sample.pdf">PDF File</a>'
-            in self.browser.contents)
+            'href="http://localhost/app/customers/K1000000/documents/%s/sample.pdf">PDF File</a>'
+            % docid in self.browser.contents)
         # Browsing the link shows a real pdf
         self.browser.open('sample.pdf')
@@ -1098,5 +1104,5 @@
         jpegfile = open(SAMPLE_IMAGE, 'rb')
         fs.createFile(file_id, jpegfile)
-        self.browser.open(self.customer_path + '/documents/d101')
+        self.browser.open(self.customer_path + '/documents/DOC1')
         self.browser.getLink("Download document slip").click()
         self.assertEqual(self.browser.headers['Status'], '200 Ok')
@@ -1114,5 +1120,6 @@
         pdffile = open(SAMPLE_PDF, 'rb')
         fs.createFile(file_id, pdffile)
-        self.browser.open(self.customer_path + '/documents/d102')
+        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
+        self.browser.open(self.customer_path + '/documents/' + docid)
         self.browser.getLink("Download document slip").click()
         self.assertEqual(self.browser.headers['Status'], '200 Ok')
@@ -1129,5 +1136,5 @@
         fs.createFile(file_id, StringIO('my sample 1'))
         result = fs.getFileByContext(self.document, attr='sample')
-        self.assertEqual(file_id, '__file-customerdocument__01000/K1000000/sample_d101_K1000000')
+        self.assertEqual(file_id, '__file-customerdocument__01000/K1000000/sample_DOC1_K1000000')
         self.assertEqual(result.read(), 'my sample 1')
         self.assertEqual(self.document.connected_files[0][1].read(), 'my sample 1')
@@ -1253,5 +1260,5 @@
         self.browser.open(self.contracts_path + '/c102/edit')
         self.browser.getControl(name="form.product_object").value = ['SAM']
-        self.browser.getControl(name="form.document_object").value = ['d101']
+        self.browser.getControl(name="form.document_object").value = ['DOC1']
         self.browser.getControl(name="form.title").value = 'My second contract'
         self.browser.getControl("Save").click()
@@ -1273,5 +1280,5 @@
             in self.browser.contents)
         self.assertTrue(
-            '<a href="http://localhost/app/customers/K1000000/documents/d101">d101 -'
+            '<a href="http://localhost/app/customers/K1000000/documents/DOC1">DOC1 -'
             in self.browser.contents)
         # Customer can submit the form. The form is also saved.
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_catalog.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_catalog.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_catalog.py	(revision 12256)
@@ -213,5 +213,5 @@
         logcontent = open(logfile).read()
         self.assertTrue(
-            'INFO - system - ObjectRemovedEvent - K1000000 - c101 - removed: d101\n'
-            in logcontent)
-
+            'INFO - system - ObjectRemovedEvent - K1000000 - c101 - removed: %s\n'
+            % self.document_id in logcontent)
+
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_document.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_document.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_document.py	(revision 12256)
@@ -156,4 +156,5 @@
         # we can't get an image filename for documents not owned by a customer
         doc = CustomerSampleDocument()
+        doc.document_id = u'DOC1'
         chooser = IFileStoreNameChooser(doc)
         # no customer can be found
@@ -168,4 +169,4 @@
         result = chooser.chooseName('sample.jpg')
         self.assertEqual(
-            result, '__file-customerdocument__01000/K1000001/sample_d123_K1000001.jpg')
+            result, '__file-customerdocument__01000/K1000001/sample_DOC1_K1000001.jpg')
         return
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_export.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_export.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_export.py	(revision 12256)
@@ -156,4 +156,5 @@
         # we can export a nearly empty document
         document = CustomerSampleDocument()
+        document.document_id = u'DOC1'
         exporter = CustomerDocumentExporter()
         exporter.export([document], self.outfile)
@@ -162,5 +163,5 @@
             result,
             'class_name,document_id,history,state,title,user_id\r\n'
-            'CustomerSampleDocument,d101,[],,,\r\n'
+            'CustomerSampleDocument,DOC1,[],,,\r\n'
             )
         return
@@ -170,5 +171,5 @@
         # set values we can expect in export file
         self.setup_customer(self.customer)
-        document = self.customer['documents']['d101']
+        document = self.customer['documents']['DOC1']
         exporter = CustomerDocumentExporter()
         exporter.export([document], self.outfile)
@@ -179,5 +180,5 @@
             )
         self.assertMatches(
-            '...CustomerSampleDocument,d101,[u\'2014-11-25 06:57:24 UTC - '
+            '...CustomerSampleDocument,DOC1,[u\'2014-11-25 06:57:24 UTC - '
             'Document created by system\'],'
             'verified,My Document,A111111...',
@@ -197,5 +198,5 @@
             in result)
         self.assertMatches(
-            '...CustomerSampleDocument,d101,[u\'2014-11-25 06:57:24 UTC - '
+            '...CustomerSampleDocument,DOC1,[u\'2014-11-25 06:57:24 UTC - '
             'Document created by system\'],'
             'verified,My Document,A111111...',
@@ -215,5 +216,5 @@
             in result)
         self.assertMatches(
-            '...CustomerSampleDocument,d101,[u\'2014-11-25 06:57:24 UTC - '
+            '...CustomerSampleDocument,DOC1,[u\'2014-11-25 06:57:24 UTC - '
             'Document created by system\'],'
             'verified,My Document,A111111...',
@@ -273,5 +274,5 @@
             'product_object,state,title\r\n'
 
-            'SampleContract,sample,c101,d101,[u\'2014-12-04 12:10:46 UTC - '
+            'SampleContract,sample,c101,DOC1,[u\'2014-12-04 12:10:46 UTC - '
             'Contract created by system\'],,'
             'SAM,created,My Contract\r\n',
@@ -292,5 +293,5 @@
             'product_object,state,title\r\n'
 
-            'SampleContract,sample,c101,d101,[u\'2014-12-04 12:10:46 UTC - '
+            'SampleContract,sample,c101,DOC1,[u\'2014-12-04 12:10:46 UTC - '
             'Contract created by system\'],,'
             'SAM,created,My Contract\r\n',
@@ -311,5 +312,5 @@
             'product_object,state,title\r\n'
 
-            'SampleContract,sample,c101,d101,[u\'2014-12-04 12:10:46 UTC - '
+            'SampleContract,sample,c101,DOC1,[u\'2014-12-04 12:10:46 UTC - '
             'Contract created by system\'],,'
             'SAM,created,My Contract\r\n',
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_interfaces.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_interfaces.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_interfaces.py	(revision 12256)
@@ -77,4 +77,5 @@
         document = createObject('waeup.CustomerSampleDocument')
         document.title = u'My Samle Document'
+        document.document_id = u'DOC1'
         self.customer['documents'].addDocument(document)
         self.document_id = document.document_id
@@ -107,4 +108,4 @@
         source = CustomerDocumentSource()
         result = source.factory.getTitle(object(), self.document)
-        self.assertEqual(result, u'd101 - My Samle Document')
+        self.assertEqual(result, u'DOC1 - My Samle Document')
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/batching.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/batching.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/batching.py	(revision 12256)
@@ -56,5 +56,4 @@
     factory_name = 'waeup.PDFDocument'
 
-    location_fields = []
     additional_fields = ['class_name']
     additional_headers = ['class_name']
@@ -66,5 +65,10 @@
 
     def entryExists(self, row, site):
-        return row['document_id'] in site['documents'].keys()
+        document_id = row.get('document_id', None)
+        cat = queryUtility(ICatalog, name='documents_catalog')
+        results = list(cat.searchResults(document_id=(document_id, document_id)))
+        if results:
+            return True
+        return False
 
     def getParent(self, row, site):
@@ -94,5 +98,5 @@
         """Update obj to the values given in row.
         """
-        items_changed = super(DocumentProcessor, self).updateEntry(
+        items_changed = super(PDFDocumentProcessor, self).updateEntry(
             obj, row, site, filename)
         # Log actions...
@@ -110,24 +114,11 @@
         # We need to check if the class_name corresponds with the
         # processor chosen. This is to avoid accidentally wrong imports.
-        if mode != 'remove':
+        if mode == 'create':
             class_name = row.get('class_name', None)
             if class_name != self.factory_name.strip('waeup.'):
                 errs.append(('class_name','wrong processor'))
-        # We have to check document_id.
         document_id = row.get('document_id', None)
-        if mode == 'create':
-            if not document_id:
-                document_id = generate_document_id()
-                conv_dict['document_id'] = document_id
-                return errs, inv_errs, conv_dict
-            cat = queryUtility(ICatalog, name='documents_catalog')
-            results = list(
-                cat.searchResults(document_id=(document_id, document_id)))
-            if results:
-                # document_id must not exist.
-                errs.append(('document_id','id exists'))
-        else:
-            if not document_id.startswith('d'):
-                errs.append(('document_id','invalid format'))
+        if ' ' in document_id:
+            errs.append(('document_id','must not contain spaces'))
         return errs, inv_errs, conv_dict
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/document.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/document.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/document.py	(revision 12256)
@@ -39,5 +39,4 @@
     IDocument, IPublicDocument, IDocumentsUtils,
     IPDFDocument, IHTMLDocument)
-from waeup.ikoba.documents.utils import generate_document_id
 
 class Document(grok.Container):
@@ -58,13 +57,4 @@
     translated_state = None
     translated_class_name = None
-
-    def __init__(self):
-        super(Document, self).__init__()
-        # The site doesn't exist in unit tests
-        try:
-            self.document_id = generate_document_id()
-        except AttributeError:
-            self.document_id = u'd123'
-        return
 
     @property
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/interfaces.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/interfaces.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/interfaces.py	(revision 12256)
@@ -38,5 +38,4 @@
 
     """
-    document_id = Attribute('Document Identifier')
     history = Attribute('Object history, a list of messages')
     state = Attribute('Returns the verification state of a document')
@@ -49,4 +48,9 @@
     connected_files = Attribute('Names of files connected to a document')
     is_verifiable = Attribute('Contract verifiable by officer')
+
+    document_id = schema.TextLine(
+        title = _(u'Document Id'),
+        required = False,
+        )
 
     title = schema.TextLine(
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_browser.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_browser.py	(revision 12256)
@@ -111,10 +111,11 @@
         self.browser.getControl(name="doctype").value = ['PDFDocument']
         self.browser.getControl(name="form.title").value = 'My PDF Document'
+        self.browser.getControl(name="form.document_id").value = 'DOC1'
         self.browser.getControl("Add document").click()
         self.assertTrue('PDF Document added.' in self.browser.contents)
-        document = self.app['documents']['d101']
+        document = self.app['documents']['DOC1']
 
         # Document can be edited
-        self.browser.getLink("d101").click()
+        self.browser.getLink("DOC1").click()
         self.browser.getLink("Manage").click()
         self.browser.getControl(name="form.title").value = 'My first doc'
@@ -122,5 +123,5 @@
         self.assertTrue('Form has been saved.' in self.browser.contents)
         self.browser.getLink("View").click()
-        self.assertEqual(self.browser.url, self.container_path + '/d101/index')
+        self.assertEqual(self.browser.url, self.container_path + '/DOC1/index')
 
         # File can be uploaded
@@ -149,5 +150,5 @@
             name='upload_pdfscanmanageupload').click()
         self.assertTrue(
-            'href="http://localhost/app/documents/d101/sample.pdf">PDF File</a>'
+            'href="http://localhost/app/documents/DOC1/sample.pdf">PDF File</a>'
             in self.browser.contents)
         # Browsing the link shows a real pdf only if the document
@@ -158,5 +159,5 @@
             in self.browser.contents)
         IWorkflowState(document).setState(PUBLISHED)
-        self.browser.open(self.container_path + '/d101/sample.pdf')
+        self.browser.open(self.container_path + '/DOC1/sample.pdf')
         self.assertEqual(
             self.browser.headers['content-type'], 'application/pdf')
@@ -164,5 +165,5 @@
         # Transitions can be performed
         self.assertEqual(document.state, 'published')
-        self.browser.open(self.container_path + '/d101')
+        self.browser.open(self.container_path + '/DOC1')
         self.browser.getLink("Transition").click()
         self.browser.getControl(name="transition").value = ['retract']
@@ -213,11 +214,12 @@
         self.browser.getControl("Add document").click()
         self.browser.getControl(name="doctype").value = ['HTMLDocument']
+        self.browser.getControl(name="form.document_id").value = 'DOC2'
         self.browser.getControl(name="form.title").value = 'My HTML Document'
         self.browser.getControl("Add document").click()
         self.assertTrue('HTML Document added.' in self.browser.contents)
-        document = self.app['documents']['d101']
+        document = self.app['documents']['DOC2']
 
         # Document can be edited
-        self.browser.getLink("d101").click()
+        self.browser.getLink("DOC2").click()
         self.browser.getLink("Manage").click()
         self.browser.getControl(name="form.title").value = 'My second doc'
@@ -230,5 +232,5 @@
         self.assertTrue('Form has been saved.' in self.browser.contents)
         self.browser.getLink("View").click()
-        self.assertEqual(self.browser.url, self.container_path + '/d101/index')
+        self.assertEqual(self.browser.url, self.container_path + '/DOC2/index')
         self.assertTrue(
             '<h1>Hello World</h1>' in self.browser.contents)
@@ -241,5 +243,5 @@
             '<h1>Hallo Welt</h1>' in self.browser.contents)
         # The content can't be rendered yet
-        self.browser.open(self.container_path + '/d101/display')
+        self.browser.open(self.container_path + '/DOC2/display')
         self.assertTrue(
             'The document requested has not yet been published'
@@ -249,5 +251,5 @@
 
         # Transitions can be performed
-        self.browser.open(self.container_path + '/d101')
+        self.browser.open(self.container_path + '/DOC2')
         self.browser.getLink("Transition").click()
         self.browser.getControl(name="transition").value = ['publish']
@@ -256,5 +258,5 @@
 
         # The content can be rendered
-        self.browser.open(self.container_path + '/d101/display')
+        self.browser.open(self.container_path + '/DOC2/display')
         self.assertTrue(
             '<h1>Hallo Welt</h1>' in self.browser.contents)
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_document.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_document.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/tests/test_document.py	(revision 12256)
@@ -72,9 +72,9 @@
         container = DocumentsContainer()
         document = createObject(u'waeup.HTMLDocument')
-        document_id = document.document_id
+        document.document_id = u'DOC'
         container.addDocument(document)
-        self.assertEqual(container[document_id], document)
+        self.assertEqual(container[document.document_id], document)
         self.assertRaises(TypeError, container.addDocument, object())
-        self.assertEqual(document_id, 'd123')
+        self.assertEqual(document.document_id, 'DOC')
         return
 
@@ -151,8 +151,9 @@
         # we can get an image filename for documents not in a container
         doc = PDFDocument()
+        doc.document_id = u'DOC'
         chooser = IFileStoreNameChooser(doc)
         result = chooser.chooseName('sample.jpg')
         # the file would be stored in a ``_default`` directory.
         self.assertEqual(
-            result, '__file-document__documents/sample_d123.jpg')
+            result, '__file-document__documents/sample_DOC.jpg')
         return
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/documents/utils.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/documents/utils.py	(revision 12255)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/documents/utils.py	(revision 12256)
@@ -26,9 +26,4 @@
 
 
-def generate_document_id():
-    new_id = grok.getSite().unique_document_id
-    return new_id
-
-
 class DocumentsUtils(grok.GlobalUtility):
     """A collection of methods subject to customization.
