Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py	(revision 12192)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/documents.py	(revision 12194)
@@ -25,4 +25,5 @@
 from zope.component.interfaces import IFactory
 from zope.interface import implementedBy
+from zope.event import notify
 
 from waeup.ikoba.image import IkobaImageFile
@@ -321,2 +322,31 @@
             file_obj.filename, file_obj.data)
 
+
+@grok.subscribe(ICustomerDocument, grok.IObjectRemovedEvent)
+def handle_document_removed(document, event):
+    """If a document is deleted, we make sure that also referrers to
+    customer contract objects are removed.
+    """
+    docid = document.document_id
+
+    # Find all customer contracts that refer to given document...
+    try:
+        contracts = document.customer['contracts'].values()
+    except AttributeError:
+        # customer not available. This might happen during tests.
+        return
+    for contract in contracts:
+        # Remove that referrer...
+        #contract.product = None
+        for key, value in contract.__dict__.items():
+            if key.endswith('_object') and \
+                getattr(value, 'document_id', None) == docid:
+                setattr(contract, key, None)
+                notify(grok.ObjectModifiedEvent(contract))
+                contract.customer.__parent__.logger.info(
+                    'ObjectRemovedEvent - %s - %s - removed: %s' % (
+                        contract.customer.customer_id,
+                        contract.contract_id,
+                        document.document_id))
+    return
+
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 12192)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_catalog.py	(revision 12194)
@@ -24,5 +24,7 @@
 from zope.component import queryUtility, createObject
 from zope.component.hooks import setSite
+from hurry.workflow.interfaces import IWorkflowState
 from waeup.ikoba.app import Company
+from waeup.ikoba.interfaces import VERIFIED
 from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
 from waeup.ikoba.customers.customer import Customer
@@ -66,17 +68,19 @@
         self.product = self.app['products'][self.product_id]
 
+        document = createObject('waeup.CustomerSampleDocument')
+        document.title = u'My Samle Document'
+        IWorkflowState(document).setState(VERIFIED)
+        self.customer['documents'].addDocument(document)
+        self.document_id = document.document_id
+        self.document = self.customer['documents'][self.document_id]
+
         contract = createObject('waeup.SampleContract')
         contract.title = u'My Samle Contract'
-        contract.product = product
+        contract.product_object = product
+        contract.document_object = document
         contract.last_product_id = product.product_id
         self.customer['contracts'].addContract(contract)
         self.contract_id = contract.contract_id
         self.contract = self.customer['contracts'][self.contract_id]
-
-        document = createObject('waeup.CustomerSampleDocument')
-        document.title = u'My Samle Document'
-        self.customer['documents'].addDocument(document)
-        self.document_id = document.document_id
-        self.document = self.customer['documents'][self.document_id]
 
         return
@@ -167,12 +171,12 @@
         assert len(results) == 1
         assert results[0] is self.customer['contracts'][self.contract_id]
-        assert results[0].product is self.product
+        assert results[0].product_object is self.product
 
     def test_product_removal(self):
         # This test does not only test catalog components, it also ensures
-        # that the product attribute of an contract is cleared
+        # that the product object attribute of a contract is cleared
         # but the last_product_id is not.
         del self.app['products'][self.product_id]
-        self.assertTrue(self.contract.product is None)
+        self.assertTrue(self.contract.product_object is None)
         self.assertEqual(self.contract.last_product_id, 'SAM')
         cat = queryUtility(ICatalog, name='contracts_catalog')
@@ -181,5 +185,5 @@
         assert len(results) == 1
         assert results[0] is self.customer['contracts'][self.contract_id]
-        assert results[0].product is None
+        assert results[0].product_object is None
         # Product removal is being logged in customers.log
         logfile = os.path.join(
@@ -190,2 +194,16 @@
             in logcontent)
 
+    def test_document_removal(self):
+        # Actually, this test does not test catalog components at all.
+        # Tt only ensures that the document object attributes of a contract
+        # are cleared, like in the test_product_removal above.
+        del self.customer['documents'][self.document_id]
+        self.assertTrue(self.contract.document_object is None)
+        # Document removal is being logged in customers.log
+        logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'customers.log')
+        logcontent = open(logfile).read()
+        self.assertTrue(
+            'INFO - system - ObjectRemovedEvent - K1000000 - c101 - removed: d101\n'
+            in logcontent)
+
