Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/__init__.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/__init__.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/__init__.py	(revision 12269)
@@ -0,0 +1,8 @@
+"""This package contains everything regarding documents.
+"""
+# Make this a package.
+from ikobacustom.skeleton.documents.document import SkeletonDocument
+
+__all__ = [
+    'SkeletonDocument',
+    ]
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/batching.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/batching.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/batching.py	(revision 12269)
@@ -0,0 +1,35 @@
+## $Id$
+##
+## Copyright (C) 2011 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
+##
+"""Batch processing for skeleton documents.
+"""
+import grok
+from waeup.ikoba.documents.batching import DocumentProcessorBase
+from ikobacustom.skeleton.documents.interfaces import ISkeletonDocument
+from ikobacustom.skeleton.interfaces import MessageFactory as _
+
+
+class SkeletonDocumentProcessor(DocumentProcessorBase):
+    """A batch processor for IHTMLDocument objects.
+    """
+    util_name = 'skeletondocumentprocessor'
+    grok.name(util_name)
+
+    name = _('Skeleton Document Processor')
+    iface = ISkeletonDocument
+
+    factory_name = 'waeup.SkeletonDocument'
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/document.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/document.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/document.py	(revision 12269)
@@ -0,0 +1,51 @@
+## $Id$
+##
+## 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
+##
+"""
+These are the documents.
+"""
+import grok
+from zope.component.interfaces import IFactory
+from zope.interface import implementedBy
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.utils.helpers import attrs_to_fields
+from waeup.ikoba.documents.document import PublicDocumentBase
+from ikobacustom.skeleton.documents.interfaces import ISkeletonDocument
+
+
+class SkeletonDocument(PublicDocumentBase):
+    """This is a document.
+    """
+    grok.implements(ISkeletonDocument)
+    grok.provides(ISkeletonDocument)
+
+SkeletonDocument = attrs_to_fields(SkeletonDocument)
+
+
+class SkeletonDocumentFactory(grok.GlobalUtility):
+    """A factory for documents.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.SkeletonDocument')
+    title = u"Create a new document.",
+    description = u"This factory instantiates new skeleton documents."
+
+    def __call__(self, *args, **kw):
+        return SkeletonDocument(*args, **kw)
+
+    def getInterfaces(self):
+        return implementedBy(SkeletonDocument)
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/export.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/export.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/export.py	(revision 12269)
@@ -0,0 +1,33 @@
+## $Id$
+##
+## 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
+##
+"""Exporters for skeleton documents.
+"""
+import grok
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.utils.helpers import iface_names
+from waeup.ikoba.documents.export import DocumentExporterBase
+from ikobacustom.skeleton.documents.interfaces import ISkeletonDocument
+
+
+class SkeletonDocumentExporter(DocumentExporterBase):
+    """Exporter for documents.
+    """
+    grok.name('skeletondocuments')
+    iface = ISkeletonDocument
+    class_name = 'SkeletonDocument'
+    title = _(u'Skeleton Documents')
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/interfaces.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/interfaces.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/interfaces.py	(revision 12269)
@@ -0,0 +1,30 @@
+## $Id$
+##
+## 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
+##
+from zope.interface import Attribute, Interface
+from zope import schema
+from waeup.ikoba.interfaces import (
+    IIkobaObject,
+    ContextualDictSourceFactoryBase)
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.documents.interfaces import IPublicDocument
+
+
+class ISkeletonDocument(IPublicDocument):
+    """A representation of a skeleton document.
+
+    """
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/__init__.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/__init__.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/__init__.py	(revision 12269)
@@ -0,0 +1,1 @@
+# Make this a package.
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/test_browser.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/test_browser.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/test_browser.py	(revision 12269)
@@ -0,0 +1,94 @@
+## $Id$
+##
+## 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
+##
+"""
+Document browser and functional tests.
+"""
+import os
+import grok
+import datetime
+from cStringIO import StringIO
+from zope.component import queryUtility, getUtility
+from zope.event import notify
+from zope.interface.verify import verifyObject, verifyClass
+from waeup.ikoba.documents.tests.test_batching import DocumentImportExportSetup
+from ikobacustom.skeleton.documents.document import SkeletonDocument
+from ikobacustom.skeleton.documents.export import SkeletonDocumentExporter
+from ikobacustom.skeleton.documents.batching import SkeletonDocumentProcessor
+from ikobacustom.skeleton.testing import FunctionalLayer
+
+
+class DocumentImportExportTest(DocumentImportExportSetup):
+
+    layer = FunctionalLayer
+
+    def setup_for_export(self):
+        document = SkeletonDocument()
+        document.document_id = u'DOC1'
+        document.title = u'My first document'
+        self.app['documents'][document.document_id] = self.document = document
+        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
+        return
+
+    def test_export_reimport_all(self):
+        # we can export all documents in a portal
+        # set values we can expect in export file
+        self.setup_for_export()
+        exporter = SkeletonDocumentExporter()
+        exporter.export_all(self.app, self.outfile)
+        result = open(self.outfile, 'rb').read()
+        self.assertEqual(result,
+            'description,document_id,title,users_with_local_roles\r\n'
+            ',DOC1,My first document,[]\r\n')
+        # We can import the same file.
+        processor = SkeletonDocumentProcessor()
+        result = processor.doImport(
+            self.outfile,
+            ['description','document_id','title','users_with_local_roles'],
+            mode='create')
+        num, num_fail, finished_path, failed_path = result
+        #content = open(failed_path).read()
+        # The object exists.
+        self.assertEqual(num_fail,1)
+        # We remove the original document.
+        del self.app['documents']['DOC1']
+        result = processor.doImport(
+            self.outfile,
+            ['description','document_id','title','users_with_local_roles'],
+            mode='create')
+        num_succ, num_fail, finished_path, failed_path = result
+        self.assertEqual(num_fail,1)
+        # ... only if we add column
+        open(self.outfile, 'wb').write(
+            'description,document_id,title,users_with_local_roles,class_name\r\n'
+            ',DOC1,My first title,[],SkeletonDocument\r\n')
+        result = processor.doImport(
+            self.outfile,
+            ['description','document_id','title','users_with_local_roles','class_name'],
+            mode='create')
+        num_succ, num_fail, finished_path, failed_path = result
+        self.assertEqual(num_fail,0)
+        # We can import the same file in update mode.
+        processor = SkeletonDocumentProcessor()
+        result = processor.doImport(
+            self.outfile,
+            ['description','document_id','title','users_with_local_roles'],
+            mode='update')
+        num_succ, num_fail, finished_path, failed_path = result
+        self.assertEqual(num_succ,1)
+        self.assertEqual(num_fail,0)
+        return
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/test_document.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/test_document.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/tests/test_document.py	(revision 12269)
@@ -0,0 +1,54 @@
+## $Id$
+##
+## 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 skeleton documents.
+"""
+from zope.interface.verify import verifyClass, verifyObject
+from zope.component import createObject
+from waeup.ikoba.documents.interfaces import IDocumentsContainer
+from waeup.ikoba.documents.container import DocumentsContainer
+
+from ikobacustom.skeleton.testing import (FunctionalLayer, FunctionalTestCase)
+from ikobacustom.skeleton.documents.document import SkeletonDocument
+from ikobacustom.skeleton.documents.interfaces import ISkeletonDocument
+
+class SkeletonDocumentTestCase(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_interfaces(self):
+        # Make sure the correct interfaces are implemented.
+        self.assertTrue(
+            verifyClass(
+                ISkeletonDocument, SkeletonDocument)
+            )
+        self.assertTrue(
+            verifyObject(
+                ISkeletonDocument, SkeletonDocument())
+            )
+        return
+
+    def test_addSkeletonDocument(self):
+        container = DocumentsContainer()
+        document = createObject(u'waeup.SkeletonDocument')
+        document.document_id = u'DOC1'
+        container.addDocument(document)
+        self.assertRaises(TypeError, container.addDocument, object())
+        self.assertEqual(document.document_id, 'DOC1')
+        self.assertEqual(container['DOC1'], document)
+        return
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/utils.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/utils.py	(revision 12269)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/documents/utils.py	(revision 12269)
@@ -0,0 +1,35 @@
+## $Id$
+##
+## 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
+##
+"""General helper functions and utilities for the documents.
+"""
+import grok
+from waeup.ikoba.documents.utils import DocumentsUtils
+from ikobacustom.skeleton.interfaces import MessageFactory as _
+
+
+class SkeletonDocumentsUtils(DocumentsUtils):
+    """A collection of methods subject to customization.
+    """
+
+    DOCTYPES_DICT = {
+        'PDFDocument': _('PDF Document'),
+        'HTMLDocument': _('HTML Document'),
+        'SkeletonDocument': _('Skeleton Document'),
+        }
+
+    SELECTABLE_DOCTYPES_DICT = DOCTYPES_DICT
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/products/export.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/products/export.py	(revision 12181)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/products/export.py	(revision 12269)
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/products/tests/test_browser.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/products/tests/test_browser.py	(revision 12181)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/products/tests/test_browser.py	(revision 12269)
@@ -60,5 +60,5 @@
             ['contract_category','product_id','title','users_with_local_roles'],
             mode='create')
-        num_succ, num_fail, finished_path, failed_path = result
+        num, num_fail, finished_path, failed_path = result
         #content = open(failed_path).read()
         # The object exists.
@@ -70,6 +70,5 @@
             ['contract_category','product_id','title','users_with_local_roles'],
             mode='create')
-        num_succ, num_fail, finished_path, failed_path = result
-        self.assertEqual(num_succ,1)
+        num, num_fail, finished_path, failed_path = result
         self.assertEqual(num_fail,0)
         # We can import the same file in update mode.
@@ -79,6 +78,6 @@
             ['contract_category','product_id','title','users_with_local_roles'],
             mode='update')
-        num_succ, num_fail, finished_path, failed_path = result
-        self.assertEqual(num_succ,1)
+        num, num_fail, finished_path, failed_path = result
+        self.assertEqual(num,1)
         self.assertEqual(num_fail,0)
         return
