Index: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/contracts.py
===================================================================
--- main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/contracts.py	(revision 12715)
+++ main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/contracts.py	(revision 12716)
@@ -20,4 +20,5 @@
 """
 import grok
+from zope.catalog.interfaces import ICatalog
 from zope.component import getUtility
 from zope.component.interfaces import IFactory
@@ -32,5 +33,5 @@
     IContractSelectProduct, ICustomersUtils, ISampleContract,
     ISampleContractProcess, ISampleContractEdit, ISampleContractOfficialUse)
-from waeup.ikoba.payments.interfaces import IPayer
+from waeup.ikoba.payments.interfaces import IPayer, IPayableFinder
 from waeup.ikoba.payments.payment import PaymentItem
 from waeup.ikoba.utils.helpers import attrs_to_fields
@@ -258,2 +259,17 @@
         IWorkflowInfo(contract).fireTransition('create')
     return
+
+
+class ContractFinder(grok.GlobalUtility):
+    grok.name('contracts_finder')
+    grok.implements(IPayableFinder)
+
+    def get_item_by_id(self, contract_id):
+        catalog = getUtility(ICatalog, 'contracts_catalog')
+        result = catalog.searchResults(
+            contract_id=(contract_id, contract_id))
+        result = [x for x in result]
+        if not result:
+            return None
+        # there should not be more than one result really.
+        return result[0]
Index: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/tests/test_contract.py
===================================================================
--- main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/tests/test_contract.py	(revision 12715)
+++ main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/tests/test_contract.py	(revision 12716)
@@ -21,5 +21,6 @@
 import decimal
 from zope.interface.verify import verifyClass, verifyObject
-from zope.component import createObject
+from zope.component import createObject, getUtility, getUtilitiesFor
+from zope.component.hooks import setSite
 from hurry.workflow.interfaces import (
     IWorkflowInfo, IWorkflowState, InvalidTransitionError)
@@ -28,8 +29,11 @@
 from waeup.ikoba.customers.contracts import (
     ContractsContainer, SampleContract, payment_items_from_contract,
-    ContractPayer,
+    ContractPayer, ContractFinder
     )
+from waeup.ikoba.app import Company
 from waeup.ikoba.customers.customer import Customer
-from waeup.ikoba.payments.interfaces import IPaymentItem, IPayer
+from waeup.ikoba.payments.interfaces import (
+    IPaymentItem, IPayer, IPayableFinder,
+    )
 from waeup.ikoba.products.productoptions import ProductOption
 from waeup.ikoba.testing import (FunctionalLayer, FunctionalTestCase)
@@ -138,2 +142,41 @@
         self.assertEqual(result.last_name, u'Tester')
         self.assertEqual(result.payer_id, customer.customer_id)
+
+    def test_contract_finder_iface(self):
+        # we have a contract finder that returns IPayableFinder data.
+        verifyClass(IPayableFinder, ContractFinder)
+
+    def test_contract_finder_registered(self):
+        # the contract finder is a utility registered on startup
+        util = getUtility(IPayableFinder, name='contracts_finder')
+        self.assertTrue(isinstance(util, ContractFinder))
+        utils = [util for name, util in getUtilitiesFor(IPayableFinder)
+                 if isinstance(util, ContractFinder)]
+        self.assertEqual(len(utils), 1)
+
+    def create_contract_and_site(self):
+        contract = SampleContract()
+        option1 = ProductOption(u"Fee 1", decimal.Decimal("31.10"), "USD")
+        option2 = ProductOption(u"Fee 2", decimal.Decimal("12.12"), "USD")
+        contract.product_options = [option1, option2]
+        contract.contract_id = u'CON1234'
+        self.getRootFolder()['app'] = Company()
+        app = self.getRootFolder()['app']
+        setSite(app)
+        return contract, app
+
+    def test_contract_finder(self):
+        # the contract finder can really find contracts
+        contract, app = self.create_contract_and_site()
+        app['mycontract'] = contract  # trigger cataloging
+        finder = ContractFinder()
+        result = finder.get_item_by_id('CON1234')
+        self.assertTrue(result is contract)
+
+    def test_contract_finder_not_stored(self):
+        # we get none if an id is not stored
+        contract, app = self.create_contract_and_site()
+        app['mycontract'] = contract  # trigger cataloging
+        finder = ContractFinder()
+        result = finder.get_item_by_id('Not-a-valid-id')
+        self.assertTrue(result is None)
Index: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/interfaces.py
===================================================================
--- main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/interfaces.py	(revision 12715)
+++ main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/interfaces.py	(revision 12716)
@@ -144,4 +144,12 @@
 
 
+class IPayableFinder(Interface):
+    """Finds payables.
+    """
+    def get_item_by_id(item_id):
+        """Get an item by its Id, or none.
+        """
+
+
 class IPaymentItem(Interface):
     """Something to sell.
