Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/contracts.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/contracts.py	(revision 12273)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/contracts.py	(revision 12273)
@@ -0,0 +1,64 @@
+## $Id: contracts.py 12258 2014-12-18 14:44:30Z henrik $
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Customer contract components.
+"""
+
+import grok
+from zope.component.interfaces import IFactory
+from zope.interface import implementedBy
+from waeup.ikoba.utils.helpers import attrs_to_fields
+from waeup.ikoba.customers.interfaces import ICustomerNavigation
+from waeup.ikoba.customers.contracts import ContractBase
+from ikobacustom.skeleton.interfaces import MessageFactory as _
+from ikobacustom.skeleton.customers.interfaces import (
+    ISkeletonContract, ISkeletonContractEdit)
+
+
+class SkeletonContract(ContractBase):
+    """This is a sample contract.
+    """
+
+    grok.implements(
+        ISkeletonContract, ISkeletonContractEdit, ICustomerNavigation)
+
+    contract_category = 'sample'
+
+    form_fields_interface = ISkeletonContract
+
+    edit_form_fields_interface = ISkeletonContractEdit
+
+    check_docs_interface = ISkeletonContract
+
+SkeletonContract = attrs_to_fields(SkeletonContract)
+
+
+# Contracts must be importable. So we might need a factory.
+class SkeletonContractFactory(grok.GlobalUtility):
+    """A factory for contracts.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.SkeletonContract')
+    title = u"Create a new contract.",
+    description = u"This factory instantiates new sample contract instances."
+
+    def __call__(self, *args, **kw):
+        return SkeletonContract(*args, **kw)
+
+    def getInterfaces(self):
+        return implementedBy(SkeletonContract)
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/documents.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/documents.py	(revision 12273)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/documents.py	(revision 12273)
@@ -0,0 +1,61 @@
+## $Id: documents.py 12256 2014-12-18 12:58:12Z henrik $
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Customer document components.
+"""
+import grok
+from zope.component.interfaces import IFactory
+from zope.interface import implementedBy
+from waeup.ikoba.utils.helpers import attrs_to_fields
+from waeup.ikoba.customers.interfaces import ICustomerNavigation
+from waeup.ikoba.customers.documents import CustomerDocumentBase
+from ikobacustom.skeleton.interfaces import MessageFactory as _
+from ikobacustom.skeleton.customers.interfaces import ISkeletonCustomerDocument
+
+
+class SkeletonCustomerDocument(CustomerDocumentBase):
+    """This is a sample customer document.
+    """
+
+    grok.implements(ISkeletonCustomerDocument, ICustomerNavigation)
+
+    # Ikoba can store any number of files per Document object.
+    # However, we highly recommend to associate and store
+    # only one file per Document object. Thus the following
+    # tuple should contain only a single filename string.
+    filenames = ('sample',)
+
+    form_fields_interface = ISkeletonCustomerDocument
+
+SkeletonCustomerDocument = attrs_to_fields(SkeletonCustomerDocument)
+
+
+# Customer documents must be importable. So we need a factory.
+class SkeletonCustomerDocumentFactory(grok.GlobalUtility):
+    """A factory for customer documents.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.SkeletonCustomerDocument')
+    title = u"Create a new document.",
+    description = u"This factory instantiates new sample document instances."
+
+    def __call__(self, *args, **kw):
+        return SkeletonCustomerDocument(*args, **kw)
+
+    def getInterfaces(self):
+        return implementedBy(SkeletonCustomerDocument)
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/interfaces.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/interfaces.py	(revision 12272)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/interfaces.py	(revision 12273)
@@ -20,5 +20,7 @@
 from waeup.ikoba.customers.interfaces import (
     ICustomer, ICustomerDocument, IContract)
-from waeup.ikoba.customers.vocabularies import CustomerDocumentSource
+from waeup.ikoba.customers.vocabularies import (
+    contextual_reg_num_source, GenderSource, nats_vocab,
+    ConCatProductSource, CustomerDocumentSource)
 from ikobacustom.skeleton.interfaces import MessageFactory as _
 
@@ -49,2 +51,19 @@
         required = False,
         )
+
+class ISkeletonContractEdit(ISkeletonContract):
+    """Interface for editing sample contract data by customers.
+
+    """
+
+    product_object = schema.Choice(
+        title = _(u'Product'),
+        source = ConCatProductSource(),
+        required = True,
+        )
+
+    document_object = schema.Choice(
+        title = _(u'Document'),
+        source = CustomerDocumentSource(),
+        required = True,
+        )
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_contract.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_contract.py	(revision 12273)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_contract.py	(revision 12273)
@@ -0,0 +1,57 @@
+## $Id: test_contract.py 12259 2014-12-18 15:47:12Z henrik $
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Tests for contracts.
+"""
+import tempfile
+import shutil
+from zope.interface.verify import verifyClass, verifyObject
+from zope.component import createObject
+from zope.component.hooks import setSite
+from zope.interface import verify
+from waeup.ikoba.app import Company
+from waeup.ikoba.customers.interfaces import ICustomerNavigation
+from waeup.ikoba.customers.interfaces import (
+    ICustomersContainer, ICustomerNavigation)
+from waeup.ikoba.customers.contracts import ContractsContainer
+
+from ikobacustom.skeleton.testing import (FunctionalLayer, FunctionalTestCase)
+from ikobacustom.skeleton.customers.contracts import SkeletonContract
+from ikobacustom.skeleton.customers.interfaces import ISkeletonContract
+
+
+class ContractsContainerTestCase(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_interfaces(self):
+        verify.verifyClass(ISkeletonContract, SkeletonContract)
+        verify.verifyClass(ICustomerNavigation, SkeletonContract)
+        verify.verifyObject(ISkeletonContract, SkeletonContract())
+        verify.verifyObject(ICustomerNavigation, SkeletonContract())
+        return
+
+    def test_addContract(self):
+        container = ContractsContainer()
+        contract = createObject(u'waeup.SkeletonContract')
+        id = contract.contract_id
+        container.addContract(contract)
+        self.assertEqual(container[id], contract)
+        self.assertRaises(TypeError, container.addContract, object())
+        self.assertEqual(contract.class_name, 'SkeletonContract')
+        return
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_customer.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_customer.py	(revision 12272)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_customer.py	(revision 12273)
@@ -60,4 +60,5 @@
     def test_addSkeletonCustomer(self):
         customer = createObject(u'waeup.Customer')
+        verify.verifyObject(ISkeletonCustomer, customer)
         self.app['customers'].addCustomer(customer)
         self.assertEqual(customer.customer_id, 'K1000000')
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_document.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_document.py	(revision 12273)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_document.py	(revision 12273)
@@ -0,0 +1,57 @@
+## $Id: test_document.py 12259 2014-12-18 15:47:12Z henrik $
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Tests for documents.
+"""
+import tempfile
+import shutil
+from zope.interface.verify import verifyClass, verifyObject
+from zope.component import createObject
+from zope.component.hooks import setSite
+from zope.interface import verify
+from waeup.ikoba.app import Company
+from waeup.ikoba.customers.interfaces import ICustomerNavigation
+from waeup.ikoba.customers.interfaces import (
+    ICustomersContainer, ICustomerNavigation)
+from waeup.ikoba.customers.documents import CustomerDocumentsContainer
+
+from ikobacustom.skeleton.testing import (FunctionalLayer, FunctionalTestCase)
+from ikobacustom.skeleton.customers.documents import SkeletonCustomerDocument
+from ikobacustom.skeleton.customers.interfaces import ISkeletonCustomerDocument
+
+
+class DocumentsContainerTestCase(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_interfaces(self):
+        verify.verifyClass(ISkeletonCustomerDocument, SkeletonCustomerDocument)
+        verify.verifyClass(ICustomerNavigation, SkeletonCustomerDocument)
+        verify.verifyObject(ISkeletonCustomerDocument, SkeletonCustomerDocument())
+        verify.verifyObject(ICustomerNavigation, SkeletonCustomerDocument())
+        return
+
+    def test_addDocument(self):
+        container = CustomerDocumentsContainer()
+        document = createObject(u'waeup.SkeletonCustomerDocument')
+        id = document.document_id
+        container.addDocument(document)
+        self.assertEqual(container[id], document)
+        self.assertRaises(TypeError, container.addDocument, object())
+        self.assertEqual(document.class_name, 'SkeletonCustomerDocument')
+        return
