Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/documents.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/documents.py	(revision 12354)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/documents.py	(revision 12355)
@@ -34,4 +34,5 @@
 
     grok.implements(ISkeletonCustomerDocument, ICustomerNavigation)
+    grok.provides(ISkeletonCustomerDocument)
 
     # Ikoba can store any number of files per Document object.
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/fileviewlets.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/fileviewlets.py	(revision 12355)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/fileviewlets.py	(revision 12355)
@@ -0,0 +1,123 @@
+## $Id: fileviewlets.py 12347 2014-12-31 08:18:54Z 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
+##
+
+import grok
+from waeup.ikoba.interfaces import MessageFactory as _
+
+from waeup.ikoba.browser.fileviewlets import (
+    FileDisplay, FileUpload, Image)
+
+from ikobacustom.skeleton.customers.documents import SkeletonCustomerDocument
+
+from waeup.ikoba.customers.browser import (
+    DocumentDisplayFormPage,
+    DocumentManageFormPage,
+    DocumentEditFormPage,
+    PDFDocumentSlipPage,)
+
+grok.templatedir('browser_templates')
+
+# File viewlets for customer documents
+
+class SampleScanManageUpload(FileUpload):
+    """Scan upload viewlet for officers.
+    """
+    grok.order(1)
+    grok.context(SkeletonCustomerDocument)
+    grok.view(DocumentManageFormPage)
+    grok.require('waeup.manageCustomer')
+    label = _(u'Sample Scan')
+    title = _(u'Sample Scan')
+    mus = 1024 * 50
+    download_name = u'sample'
+    tab_redirect = '#tab2'
+
+
+class SampleScanEditUpload(SampleScanManageUpload):
+    """Scan upload viewlet for customer.
+    """
+    grok.view(DocumentEditFormPage)
+    grok.require('waeup.handleCustomer')
+
+
+class SampleScanDisplay(FileDisplay):
+    """Scan display viewlet.
+    """
+    grok.order(1)
+    grok.context(SkeletonCustomerDocument)
+    grok.require('waeup.viewCustomer')
+    grok.view(DocumentDisplayFormPage)
+    label = _(u'Sample Scan')
+    title = _(u'Sample Scan')
+    download_name = u'sample'
+
+
+class SampleScanImage(Image):
+    """Scan document.
+    """
+    grok.name('sample')
+    grok.context(SkeletonCustomerDocument)
+    grok.require('waeup.viewCustomer')
+    download_name = u'sample'
+
+class SampleScanPDFSlip(SampleScanDisplay):
+    grok.view(PDFDocumentSlipPage)
+
+
+class PDFScanManageUpload(FileUpload):
+    """Scan upload viewlet for officers.
+    """
+    grok.view(DocumentManageFormPage)
+    grok.context(SkeletonCustomerDocument)
+    grok.require('waeup.manageCustomer')
+    label = _(u'PDF File')
+    title = _(u'PDF File')
+    mus = 1024 * 200
+    download_name = u'sample.pdf'
+    tab_redirect = '#tab2'
+
+
+class PDFScanEditUpload(PDFScanManageUpload):
+    """Scan upload viewlet for customer.
+    """
+    grok.view(DocumentEditFormPage)
+    grok.require('waeup.handleCustomer')
+
+
+class PDFScanDisplay(FileDisplay):
+    """Scan display viewlet.
+    """
+    grok.order(1)
+    grok.context(SkeletonCustomerDocument)
+    grok.require('waeup.viewCustomer')
+    grok.view(DocumentDisplayFormPage)
+    label = _(u'PDF Scan')
+    title = _(u'PDF Scan')
+    download_name = u'sample.pdf'
+
+
+class PDFScanImage(Image):
+    """Scan document.
+    """
+    grok.name('sample.pdf')
+    grok.context(SkeletonCustomerDocument)
+    grok.require('waeup.viewCustomer')
+    download_name = u'sample.pdf'
+
+class PDFScanSlip(PDFScanDisplay):
+    grok.view(PDFDocumentSlipPage)
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_browser.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_browser.py	(revision 12354)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/tests/test_browser.py	(revision 12355)
@@ -29,4 +29,5 @@
 from hurry.workflow.interfaces import IWorkflowState
 from waeup.ikoba.customers.tests.test_batching import CustomerImportExportSetup
+from waeup.ikoba.customers.tests.test_browser import CustomersFullSetup
 from ikobacustom.skeleton.customers.export import (
     SkeletonCustomerExporter,
@@ -39,4 +40,7 @@
 from ikobacustom.skeleton.testing import FunctionalLayer
 
+SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
+SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
+SAMPLE_PDF = os.path.join(os.path.dirname(__file__), 'test_pdf.pdf')
 
 class CustomerImportExportTest(CustomerImportExportSetup):
@@ -202,2 +206,48 @@
         self.assertEqual(num_fail,0)
         return
+
+class DocumentUITests(CustomersFullSetup):
+    # Tests for customer document related views and pages
+
+    layer = FunctionalLayer
+
+    def test_manage_upload_pdf_file(self):
+        # Managers can upload a file via the DocumentManageFormPage
+        # The image is stored even if form has errors
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.customer_path + '/documents')
+        self.browser.getControl("Add document").click()
+        self.browser.getControl(name="doctype").value = ['SkeletonCustomerDocument']
+        self.browser.getControl(name="form.title").value = 'My Skeleton Document'
+        self.browser.getControl("Add document").click()
+        docid = [i for i in self.customer['documents'].keys() if len(i) > 10][0]
+        self.browser.open(self.documents_path + '/%s/manage' % docid)
+        # Create a pseudo image file and select it to be uploaded
+        image = open(SAMPLE_IMAGE, 'rb')
+        ctrl = self.browser.getControl(name='pdfscanmanageupload')
+        file_ctrl = ctrl.mech_control
+        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
+        self.browser.getControl(
+            name='upload_pdfscanmanageupload').click()
+        self.assertTrue(
+            'pdf file extension expected' in self.browser.contents)
+        ctrl = self.browser.getControl(name='pdfscanmanageupload')
+        file_ctrl = ctrl.mech_control
+        file_ctrl.add_file(image, filename='my_sample_scan.pdf')
+        self.browser.getControl(
+            name='upload_pdfscanmanageupload').click()
+        self.assertTrue(
+            'Could not determine file type' in self.browser.contents)
+        pdf = open(SAMPLE_PDF, 'rb')
+        ctrl = self.browser.getControl(name='pdfscanmanageupload')
+        file_ctrl = ctrl.mech_control
+        file_ctrl.add_file(pdf, filename='my_sample_scan.pdf')
+        self.browser.getControl(
+            name='upload_pdfscanmanageupload').click()
+        self.assertTrue(
+            'href="http://localhost/app/customers/K1000000/documents/%s/sample.pdf">PDF File</a>'
+            % docid in self.browser.contents)
+        # Browsing the link shows a real pdf
+        self.browser.open('sample.pdf')
+        self.assertEqual(
+            self.browser.headers['content-type'], 'application/pdf')
Index: main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/utils.py
===================================================================
--- main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/utils.py	(revision 12354)
+++ main/ikobacustom.skeleton/trunk/src/ikobacustom/skeleton/customers/utils.py	(revision 12355)
@@ -19,4 +19,5 @@
 """
 
+from copy import deepcopy
 from waeup.ikoba.customers.utils import CustomersUtils
 from ikobacustom.skeleton.interfaces import MessageFactory as _
@@ -31,5 +32,5 @@
         'CustomerPDFDocument': _('PDF Document'),
 
-        'SkeletonSampleDocument': _('Skeleton Document'),
+        'SkeletonCustomerDocument': _('Skeleton Document'),
         }
 
@@ -40,5 +41,5 @@
         }
 
-    SELECTABLE_DOCTYPES_DICT = DOCTYPES_DICT
+    SELECTABLE_DOCTYPES_DICT = deepcopy(DOCTYPES_DICT)
 
-    SELECTABLE_CONTYPES_DICT = CONTYPES_DICT
+    SELECTABLE_CONTYPES_DICT = deepcopy(CONTYPES_DICT)
