Index: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/customer.py
===================================================================
--- main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/customer.py	(revision 12735)
+++ main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/customer.py	(revision 12738)
@@ -25,5 +25,6 @@
 from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
 from zope.password.interfaces import IPasswordManager
-from zope.component import getUtility, createObject
+from zope.catalog.interfaces import ICatalog
+from zope.component import getUtility, createObject, queryUtility
 from zope.component.interfaces import IFactory
 from zope.interface import implementedBy
@@ -43,4 +44,5 @@
 from waeup.ikoba.customers.documents import CustomerDocumentsContainer
 from waeup.ikoba.customers.contracts import ContractsContainer
+from waeup.ikoba.payments.interfaces import IPayer, IPayerFinder
 from waeup.ikoba.utils.helpers import attrs_to_fields, now, copy_filesystem_tree
 
@@ -399,2 +401,40 @@
         return file, path, IkobaImageFile(
             file_obj.filename, file_obj.data)
+
+
+class CustomerPayer(grok.Adapter):
+    """Adapter to turn customers into IPayers.
+    """
+    grok.implements(IPayer)
+    grok.context(ICustomer)
+
+    @property
+    def first_name(self):
+        return getattr(self.context, 'firstname', None)
+
+    @property
+    def last_name(self):
+        return getattr(self.context, 'lastname', None)
+
+    @property
+    def payer_id(self):
+        return getattr(self.context, 'customer_id', None)
+
+
+class CustomerFinder(grok.GlobalUtility):
+    """Find customers.
+    """
+    grok.name('customer_finder')
+    grok.implements(IPayerFinder)
+
+    def get_payer_by_id(self, customer_id):
+        catalog = queryUtility(ICatalog, 'customers_catalog')
+        if catalog is None:
+            return None
+        result = catalog.searchResults(
+            customer_id=(customer_id, customer_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_customer.py
===================================================================
--- main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/tests/test_customer.py	(revision 12735)
+++ main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/tests/test_customer.py	(revision 12738)
@@ -24,5 +24,8 @@
 from cStringIO import StringIO
 from datetime import tzinfo
-from zope.component import getUtility, queryUtility, createObject
+from zope.component import (
+    getUtility, queryUtility, createObject, getUtilitiesFor,
+    )
+from zope.component.hooks import setSite
 from zope.catalog.interfaces import ICatalog
 from zope.component.interfaces import IFactory
@@ -31,9 +34,13 @@
 from zope.schema.interfaces import RequiredMissing
 from waeup.ikoba.interfaces import IExtFileStore, IFileStoreNameChooser
+from waeup.ikoba.app import Company
 from waeup.ikoba.customers.customer import (
-    Customer, CustomerFactory, handle_customer_removed, path_from_custid)
+    Customer, CustomerFactory, handle_customer_removed, path_from_custid,
+    CustomerPayer, CustomerFinder,
+    )
 from waeup.ikoba.customers.interfaces import (
     ICustomer, ICustomerNavigation, ICustomersUtils)
 from waeup.ikoba.customers.tests.test_batching import CustomerImportExportSetup
+from waeup.ikoba.payments.interfaces import IPayer, IPayerFinder
 from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
 
@@ -92,4 +99,62 @@
 
 
+class TestCustomerHelpers(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_payer_adapter(self):
+        # we can adapt ICustomer to IPayer (i.e. create a payer)
+        customer = Customer()
+        customer.firstname, customer.lastname = u'Anna', u'Tester'
+        result = IPayer(customer)
+        self.assertTrue(isinstance(result, CustomerPayer))
+        verify.verifyObject(IPayer, result)
+        self.assertEqual(result.first_name, u'Anna')
+        self.assertEqual(result.last_name, u'Tester')
+        self.assertEqual(result.payer_id, customer.customer_id)
+
+    def test_customer_finder_iface(self):
+        # we have a customer finder that returns IPayableFinder data.
+        verify.verifyClass(IPayerFinder, CustomerFinder)
+
+    def test_customer_finder_registered(self):
+        # the customer finder is a utility registered on startup
+        util = getUtility(IPayerFinder, name='customer_finder')
+        self.assertTrue(isinstance(util, CustomerFinder))
+        utils = [util for name, util in getUtilitiesFor(IPayerFinder)
+                 if isinstance(util, CustomerFinder)]
+        self.assertEqual(len(utils), 1)
+
+    def create_customer_and_site(self):
+        customer = Customer()
+        customer.customer_id = u'CUST1'
+        self.getRootFolder()['app'] = Company()
+        app = self.getRootFolder()['app']
+        setSite(app)
+        return customer, app
+
+    def test_customer_finder(self):
+        # the customer finder can really find customers
+        customer, app = self.create_customer_and_site()
+        app['mycustomer'] = customer  # trigger cataloging
+        finder = CustomerFinder()
+        result = finder.get_payer_by_id('CUST1')
+        self.assertTrue(result is customer)
+
+    def test_customer_finder_not_stored(self):
+        # we get none if an id is not stored
+        customer, app = self.create_customer_and_site()
+        app['mycustomer'] = customer  # trigger cataloging
+        finder = CustomerFinder()
+        result = finder.get_payer_by_id('Not-a-valid-id')
+        self.assertTrue(result is None)
+
+    def test_customer_finder_no_catalog(self):
+        # customer finder does not complain about missing catalog
+        finder = CustomerFinder()
+        result = finder.get_payer_by_id('CUST1')
+        self.assertTrue(result is None)
+
+
 class CustomerRemovalTests(CustomerImportExportSetup):
     # Test handle_customer_removed
