Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/applications.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/applications.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/applications.py	(revision 12090)
@@ -129,6 +129,6 @@
     def translated_class_name(self):
         try:
-            DOCTYPES_DICT = getUtility(ICustomersUtils).DOCTYPES_DICT
-            return DOCTYPES_DICT[self.class_name]
+            APPTYPES_DICT = getUtility(ICustomersUtils).APPTYPES_DICT
+            return APPTYPES_DICT[self.class_name]
         except KeyError:
             return
@@ -157,2 +157,10 @@
         return implementedBy(SampleApplication)
 
+@grok.subscribe(IApplication, grok.IObjectAddedEvent)
+def handle_document_added(application, event):
+    """If an application is added the transition create is fired.
+    The latter produces a logging message.
+    """
+    if IWorkflowState(application).getState() is None:
+        IWorkflowInfo(application).fireTransition('create')
+    return
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12090)
@@ -51,5 +51,5 @@
     ICustomer, ICustomersContainer, ICustomerRequestPW, ICustomersUtils,
     ICustomerDocument, ICustomerDocumentsContainer, ICustomerCreate,
-    ICustomerPDFDocument
+    ICustomerPDFDocument, IApplicationsContainer, IApplication
     )
 from waeup.ikoba.customers.catalog import search
@@ -1024,2 +1024,315 @@
             self.context.customer, customerview,
             omit_fields=self.omit_fields)
+
+# Pages for customer applications
+
+class ApplicationsBreadcrumb(Breadcrumb):
+    """A breadcrumb for the applications container.
+    """
+    grok.context(IApplicationsContainer)
+    title = _('Applications')
+
+
+class ApplicationBreadcrumb(Breadcrumb):
+    """A breadcrumb for the customer container.
+    """
+    grok.context(IApplication)
+
+    @property
+    def title(self):
+        return self.context.application_id
+
+
+class ApplicationsManageFormPage(IkobaEditFormPage):
+    """ Page to manage the customer applications
+
+    This manage form page is for both customers and customers officers.
+    """
+    grok.context(IApplicationsContainer)
+    grok.name('index')
+    grok.require('waeup.viewCustomer')
+    form_fields = grok.AutoFields(IApplicationsContainer)
+    grok.template('applicationsmanagepage')
+    pnav = 4
+
+    @property
+    def manage_applications_allowed(self):
+        return checkPermission('waeup.editApplications', self.context)
+
+    def unremovable(self, application):
+        usertype = getattr(self.request.principal, 'user_type', None)
+        if not usertype:
+            return False
+        if not self.manage_applications_allowed:
+            return True
+        return (self.request.principal.user_type == 'customer' and \
+            application.state in (APPROVED, REJECTED, EXPIRED))
+
+    @property
+    def label(self):
+        return _('${a}: Applications',
+            mapping = {'a':self.context.__parent__.display_fullname})
+
+    @jsaction(_('Remove selected applications'))
+    def delApplication(self, **data):
+        form = self.request.form
+        if 'val_id' in form:
+            child_id = form['val_id']
+        else:
+            self.flash(_('No application selected.'), type="warning")
+            self.redirect(self.url(self.context))
+            return
+        if not isinstance(child_id, list):
+            child_id = [child_id]
+        deleted = []
+        for id in child_id:
+            # Customers are not allowed to remove used applications
+            application = self.context.get(id, None)
+            if application is not None and not self.unremovable(application):
+                del self.context[id]
+                deleted.append(id)
+        if len(deleted):
+            self.flash(_('Successfully removed: ${a}',
+                mapping = {'a': ', '.join(deleted)}))
+            self.context.writeLogMessage(
+                self,'removed: %s' % ', '.join(deleted))
+        self.redirect(self.url(self.context))
+        return
+
+
+class ApplicationAddFormPage(IkobaAddFormPage):
+    """ Page to add an application
+    """
+    grok.context(IApplicationsContainer)
+    grok.name('addapp')
+    grok.template('applicationaddform')
+    grok.require('waeup.editApplications')
+    form_fields = grok.AutoFields(IApplication)
+    label = _('Add application')
+    pnav = 4
+
+    @property
+    def selectable_apptypes(self):
+        apptypes = getUtility(ICustomersUtils).SELECTABLE_APPTYPES_DICT
+        return sorted(apptypes.items())
+
+    @action(_('Create application'), style='primary')
+    def createApplication(self, **data):
+        form = self.request.form
+        customer = self.context.__parent__
+        apptype = form.get('apptype', None)
+        # Here we can create various instances of Application derived
+        # classes depending on the apptype parameter given in form.
+        application = createObject('waeup.%s' % apptype)
+        self.context.addApplication(application)
+        apptype = getUtility(ICustomersUtils).SELECTABLE_APPTYPES_DICT[apptype]
+        self.flash(_('${a} created.',
+            mapping = {'a': apptype}))
+        self.context.writeLogMessage(
+            self,'added: %s %s' % (apptype, application.application_id))
+        self.redirect(self.url(self.context))
+        return
+
+    @action(_('Cancel'), validator=NullValidator)
+    def cancel(self, **data):
+        self.redirect(self.url(self.context))
+
+
+class ApplicationDisplayFormPage(IkobaDisplayFormPage):
+    """ Page to view a application
+    """
+    grok.context(IApplication)
+    grok.name('index')
+    grok.require('waeup.viewCustomer')
+    grok.template('applicationpage')
+    form_fields = grok.AutoFields(IApplication).omit('last_transition_date')
+    pnav = 4
+
+    #@property
+    #def label(self):
+    #    return _('${a}: Application ${b}', mapping = {
+    #        'a':self.context.customer.display_fullname,
+    #        'b':self.context.application_id})
+
+    @property
+    def label(self):
+        return _('${a}', mapping = {'a':self.context.title})
+
+
+class ApplicationManageFormPage(IkobaEditFormPage):
+    """ Page to edit a application
+    """
+    grok.context(IApplication)
+    grok.name('manage')
+    grok.require('waeup.manageCustomer')
+    grok.template('applicationeditpage')
+    form_fields = grok.AutoFields(IApplication).omit('last_transition_date')
+    pnav = 4
+    deletion_warning = _('Are you sure?')
+
+    #@property
+    #def label(self):
+    #    return _('${a}: Application ${b}', mapping = {
+    #        'a':self.context.customer.display_fullname,
+    #        'b':self.context.application_id})
+
+    @property
+    def label(self):
+        return _('${a}', mapping = {'a':self.context.title})
+
+    @action(_('Save'), style='primary')
+    def save(self, **data):
+        msave(self, **data)
+        return
+
+
+class ApplicationEditFormPage(ApplicationManageFormPage):
+    """ Page to edit a application
+    """
+    grok.name('edit')
+    grok.require('waeup.handleCustomer')
+
+    def update(self):
+        if not self.context.is_editable:
+            emit_lock_message(self)
+            return
+        return super(ApplicationEditFormPage, self).update()
+
+    @action(_('Save'), style='primary')
+    def save(self, **data):
+        msave(self, **data)
+        return
+
+    @action(_('Final Submit'), warning=WARNING)
+    def finalsubmit(self, **data):
+        msave(self, **data)
+        IWorkflowInfo(self.context).fireTransition('submit')
+        self.flash(_('Form has been submitted.'))
+        self.redirect(self.url(self.context))
+        return
+
+
+class ApplicationTriggerTransitionFormPage(IkobaEditFormPage):
+    """ View to trigger customer application transitions
+    """
+    grok.context(IApplication)
+    grok.name('trigtrans')
+    grok.require('waeup.triggerTransition')
+    grok.template('trigtrans')
+    label = _('Trigger application transition')
+    pnav = 4
+
+    def update(self):
+        return super(IkobaEditFormPage, self).update()
+
+    def getTransitions(self):
+        """Return a list of dicts of allowed transition ids and titles.
+
+        Each list entry provides keys ``name`` and ``title`` for
+        internal name and (human readable) title of a single
+        transition.
+        """
+        wf_info = IWorkflowInfo(self.context)
+        allowed_transitions = [t for t in wf_info.getManualTransitions()]
+        return [dict(name='', title=_('No transition'))] +[
+            dict(name=x, title=y) for x, y in allowed_transitions]
+
+    @action(_('Save'), style='primary')
+    def save(self, **data):
+        form = self.request.form
+        if 'transition' in form and form['transition']:
+            transition_id = form['transition']
+            wf_info = IWorkflowInfo(self.context)
+            wf_info.fireTransition(transition_id)
+        return
+
+class PDFApplicationsOverviewPage(UtilityView, grok.View):
+    """Deliver an overview slip.
+    """
+    grok.context(IApplicationsContainer)
+    grok.name('overview_slip.pdf')
+    grok.require('waeup.viewCustomer')
+    prefix = 'form'
+
+    omit_fields = ('suspended', 'sex',
+                   'suspended_comment',)
+
+    form_fields = None
+
+    @property
+    def label(self):
+        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
+        return translate(_('Applications of'),
+            'waeup.ikoba', target_language=portal_language) \
+            + ' %s' % self.context.customer.display_fullname
+
+    @property
+    def tabletitle(self):
+        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
+        tabletitle = []
+        tabletitle.append(translate(_('Customer Applications'), 'waeup.ikoba',
+            target_language=portal_language))
+        return tabletitle
+
+    def render(self):
+        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
+        Id = translate(_('Id'), 'waeup.ikoba', target_language=portal_language)
+        Title = translate(_('Title'), 'waeup.ikoba', target_language=portal_language)
+        Type = translate(_('Type'), 'waeup.ikoba', target_language=portal_language)
+        State = translate(_('State'), 'waeup.ikoba', target_language=portal_language)
+        LT = translate(_('Last Transition'), 'waeup.ikoba', target_language=portal_language)
+        tableheader = []
+        tabledata = []
+        contenttitle = []
+        for i in range(1,3):
+            tabledata.append(sorted(
+                [value for value in self.context.values()]))
+            tableheader.append([(Id, 'application_id', 2),
+                             (Title, 'title', 6),
+                             (Type, 'translated_class_name', 6),
+                             (State, 'translated_state', 2),
+                             (LT, 'formatted_transition_date', 3),
+                             ])
+        customerview = CustomerBasePDFFormPage(self.context.customer,
+            self.request, self.omit_fields)
+        customers_utils = getUtility(ICustomersUtils)
+        return customers_utils.renderPDF(
+            self, 'overview_slip.pdf',
+            self.context.customer, customerview,
+            tableheader=tableheader,
+            tabledata=tabledata,
+            omit_fields=self.omit_fields)
+
+
+class PDFApplicationSlipPage(UtilityView, grok.View):
+    """Deliver pdf file including metadata.
+    """
+    grok.context(IApplication)
+    grok.name('application_slip.pdf')
+    grok.require('waeup.viewCustomer')
+    prefix = 'form'
+
+    omit_fields = ('suspended', 'sex',
+                   'suspended_comment',)
+
+    #form_fields = grok.AutoFields(ICustomerPDFApplication).omit(
+    #    'last_transition_date')
+    form_fields =()
+
+    @property
+    def label(self):
+        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
+        return '%s of %s\nTitle: %s' % (
+            self.context.translated_class_name,
+            self.context.customer.display_fullname,
+            self.context.title)
+
+    def render(self):
+        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
+        customerview = CustomerBasePDFFormPage(self.context.customer,
+            self.request, self.omit_fields)
+        customers_utils = getUtility(ICustomersUtils)
+        return customers_utils.renderPDF(
+            self, 'application_slip.pdf',
+            self.context.customer, customerview,
+            omit_fields=self.omit_fields)
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationaddform.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationaddform.pt	(revision 12090)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationaddform.pt	(revision 12090)
@@ -0,0 +1,26 @@
+<form action="." tal:attributes="action request/URL" method="post"
+      enctype="multipart/form-data" i18n:domain="waeup.ikoba">
+  <table class="form-table">
+    <tbody>
+      <tr>
+        <td class="fieldname">
+          <span i18n:translate="">Application Type</span>:
+        </td>
+        <td>
+          <select id="apptype" name="apptype" size="1"
+                  class="form-control half">
+            <option tal:repeat="item view/selectable_apptypes"
+                    tal:attributes="value python:item[0]">
+              <span tal:replace="python:item[1]">APPTYPE</span>
+            </option>
+          </select>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  <div tal:condition="view/availableActions">
+    <input tal:repeat="action view/actions"
+           tal:replace="structure action/render"
+           />
+  </div>
+</form>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationeditpage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationeditpage.pt	(revision 12090)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationeditpage.pt	(revision 12090)
@@ -0,0 +1,41 @@
+<form action="." tal:attributes="action request/URL" method="post"
+      i18n:domain="waeup.ikoba" enctype="multipart/form-data">
+
+  <ul class="tabs nav nav-tabs" data-tabs="tabs">
+    <li class="active">
+      <a href="#tab1" data-toggle="tab">
+        <span i18n:translate="">Metadata</span>
+      </a>
+    </li>
+    <li>
+      <a href="#tab2" data-toggle="tab">
+        <span i18n:translate="">Documents</span>
+      </a>
+    </li>
+  </ul>
+  <div class="tab-content">
+    <div id="tab1" class="active tab-pane">
+      <br />
+      <table class="form-table">
+        <tbody>
+          <tal:widgets content="structure provider:widgets" />
+        </tbody>
+      </table>
+
+      <div tal:condition="view/availableActions">
+        <input tal:repeat="action view/actions"
+               tal:replace="structure action/render"
+               />
+      </div>
+    </div>
+
+    <div id="tab2" class="tab-pane">
+      <br />
+      <table class="form-table">
+        <tbody>
+
+        </tbody>
+      </table>
+    </div>
+  </div>
+</form>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationpage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationpage.pt	(revision 12090)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationpage.pt	(revision 12090)
@@ -0,0 +1,24 @@
+<div class="wfstatus-sub"  i18n:domain="waeup.ikoba">
+  Application State: <span tal:replace="context/translated_state">
+    APPLICATIONSTATE</span>
+</div>
+
+<div class="workflow">
+  <div tal:repeat="msg context/history/messages">
+    <span tal:replace="msg">MESSAGE</span><br />
+  </div>
+</div>
+
+<table class="form-table" i18n:domain="waeup.ikoba">
+  <tbody>
+    <tr>
+      <td i18n:translate="" class="fieldname">
+        Application Type:
+      </td>
+      <td>
+        <span tal:content="context/translated_class_name">CLASSNAME</span>
+      </td>
+    </tr>
+    <tal:widgets content="structure provider:widgets" />
+  </tbody>
+</table>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationsmanagepage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationsmanagepage.pt	(revision 12090)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/applicationsmanagepage.pt	(revision 12090)
@@ -0,0 +1,51 @@
+<form action="." tal:attributes="action request/URL" method="POST"
+      i18n:domain="waeup.ikoba" enctype="multipart/form-data">
+
+  <table class="ikoba-data-table dataTableManage">
+    <thead>
+    <tr>
+      <th>&nbsp;</th>
+      <th i18n:translate="">Id</th>
+      <th i18n:translate="">Title</th>
+      <th i18n:translate="">Type</th>
+      <th i18n:translate="">State</th>
+      <th i18n:translate="">Last Transition</th>
+    </tr>
+    </thead>
+    <tbody>
+      <tr tal:repeat="cl context/values">
+         <td>
+          <input type="checkbox"
+    		 name="val_id"
+    		 tal:attributes="value cl/__name__"
+         tal:condition="python: not view.unremovable(cl)" />
+        </td>
+        <td>
+          <a tal:attributes="href python: view.url(cl)">
+          <span tal:content="cl/application_id">APPID</span></a>
+        </td>
+        <td>
+          <span tal:content="cl/title">TITLE</span>
+        </td>
+        <td>
+          <span tal:content="cl/translated_class_name">CLASSNAME</span>
+        </td>
+        <td>
+          <span tal:content="cl/translated_state">STATE</span>
+        </td>
+        <td>
+          <span tal:content="cl/formatted_transition_date">
+              LASTTRANSITIONDATE
+          </span>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <div tal:condition="python: view.availableActions and view.manage_applications_allowed">
+    <span tal:repeat="action view/actions"
+          tal:omit-tag="">
+      <input tal:replace="structure action/render"/>
+    </span>
+  </div>
+</form>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/documentaddform.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/documentaddform.pt	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/documentaddform.pt	(revision 12090)
@@ -1,9 +1,9 @@
 <form action="." tal:attributes="action request/URL" method="post"
-      enctype="multipart/form-data">
+      enctype="multipart/form-data" i18n:domain="waeup.ikoba">
   <table class="form-table">
     <tbody>
       <tr>
         <td class="fieldname">
-          <span>Document Type</span>:
+          <span i18n:translate="">Document Type</span>:
         </td>
         <td>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/documentpage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/documentpage.pt	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/documentpage.pt	(revision 12090)
@@ -1,3 +1,3 @@
-<div class="wfstatus-sub"  i18n:domain="waeup.kofa">
+<div class="wfstatus-sub"  i18n:domain="waeup.ikoba">
   Document State: <span tal:replace="context/translated_state">
     VERIFICATIONSTATE</span>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/container.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/container.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/container.py	(revision 12090)
@@ -1,3 +1,3 @@
-## $Id: container.py 8737 2012-06-17 07:32:08Z henrik $
+## $Id$
 ##
 ## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
@@ -66,10 +66,4 @@
         return new_id
 
-    def archive(self, id=None):
-        raise NotImplementedError()
-
-    def clear(self, id=None, archive=True):
-        raise NotImplementedError()
-
     def addCustomer(self, customer):
         """Add a customer with subcontainers.
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/customer.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/customer.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/customer.py	(revision 12090)
@@ -43,4 +43,5 @@
 from waeup.ikoba.customers.utils import generate_customer_id, path_from_custid
 from waeup.ikoba.customers.documents import CustomerDocumentsContainer
+from waeup.ikoba.customers.applications import ApplicationsContainer
 from waeup.ikoba.utils.helpers import attrs_to_fields, now, copy_filesystem_tree
 
@@ -183,4 +184,6 @@
     documents = CustomerDocumentsContainer()
     customer['documents'] = documents
+    applications = ApplicationsContainer()
+    customer['applications'] = applications
     return
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12090)
@@ -47,34 +47,4 @@
         """
 
-    def archive(id=None):
-        """Create on-dist archive of customers.
-
-        If id is `None`, all customers are archived.
-
-        If id contains a single id string, only the respective
-        customers are archived.
-
-        If id contains a list of id strings all of the respective
-        customers types are saved to disk.
-        """
-
-    def clear(id=None, archive=True):
-        """Remove customers of type given by 'id'.
-
-        Optionally archive the customers.
-
-        If id is `None`, all customers are archived.
-
-        If id contains a single id string, only the respective
-        customers are archived.
-
-        If id contains a list of id strings all of the respective
-        customer types are saved to disk.
-
-        If `archive` is ``False`` none of the archive-handling is done
-        and respective customers are simply removed from the
-        database.
-        """
-
     unique_customer_id = Attribute("""A unique customer id.""")
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/permissions.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/permissions.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/permissions.py	(revision 12090)
@@ -48,4 +48,8 @@
 
 
+class EditApplications(grok.Permission):
+    grok.name('waeup.editApplications')
+
+
 class UploadCustomerFile(grok.Permission):
     grok.name('waeup.uploadCustomerFile')
@@ -93,5 +97,6 @@
                      'waeup.manageCustomer', 'waeup.viewCustomersContainer',
                      'waeup.editCustomerDocuments', 'waeup.uploadCustomerFile',
-                     'waeup.viewCustomersTab', 'waeup.triggerTransition')
+                     'waeup.viewCustomersTab', 'waeup.triggerTransition',
+                     'waeup.editApplications')
 
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_container.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_container.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_container.py	(revision 12090)
@@ -1,3 +1,3 @@
-## $Id: test_container.py 7811 2012-03-08 19:00:51Z uli $
+## $Id$
 ##
 ## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
@@ -68,17 +68,4 @@
         return
 
-    def test_base(self):
-        # We cannot call the fundamental methods of a base in that case
-        container = CustomersContainer()
-        self.assertRaises(
-            NotImplementedError, container.archive)
-        self.assertRaises(
-            NotImplementedError, container.clear)
-        # We cannot add arbitrary objects
-        #department = Department()
-        #self.assertRaises(
-        #    TypeError, container.addCustomer, department)
-
-
     def test_logger(self):
         # We can get a logger from root
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12090)
@@ -33,5 +33,7 @@
 from waeup.ikoba.interfaces import MessageFactory as _
 from waeup.ikoba.interfaces import (
-    CREATED, STARTED, REQUESTED, APPROVED, IIkobaUtils, IExtFileStore)
+    STARTED, CREATED, REQUESTED, APPROVED, SUBMITTED, VERIFIED, REJECTED,
+    EXPIRED,
+    IIkobaUtils, IExtFileStore)
 from waeup.ikoba.customers.interfaces import ICustomersUtils
 from waeup.ikoba.browser.interfaces import IPDFCreator
@@ -300,4 +302,9 @@
 
     TRANSLATED_APPLICATION_STATES = {
+        CREATED: _('created'),
+        SUBMITTED: _('submitted for approval'),
+        APPROVED: _('approved'),
+        REJECTED: _('rejected'),
+        EXPIRED:_('expired')
         }
 
@@ -307,5 +314,11 @@
         }
 
+    APPTYPES_DICT = {
+        'SampleApplication': 'Sample Application',
+        }
+
     SELECTABLE_DOCTYPES_DICT = DOCTYPES_DICT
+
+    SELECTABLE_APPTYPES_DICT = APPTYPES_DICT
 
     def getPDFCreator(self, context=None):
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/viewlets.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/viewlets.py	(revision 12089)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/viewlets.py	(revision 12090)
@@ -27,9 +27,12 @@
 from waeup.ikoba.customers.interfaces import (
     ICustomer, ICustomersContainer,
-    ICustomerDocumentsContainer, ICustomerDocument)
+    ICustomerDocumentsContainer, ICustomerDocument,
+    IApplicationsContainer, IApplication)
 from waeup.ikoba.customers.browser import (
     CustomersContainerPage, CustomersContainerManagePage,
     CustomerBaseDisplayFormPage,
-    DocumentsManageFormPage, DocumentDisplayFormPage, DocumentManageFormPage)
+    DocumentsManageFormPage, DocumentDisplayFormPage, DocumentManageFormPage,
+    ApplicationsManageFormPage, ApplicationDisplayFormPage,
+    ApplicationManageFormPage)
 
 grok.context(IIkobaObject)  # Make IIkobaObject the default context
@@ -107,5 +110,6 @@
         targets += [
             {'url':customer_url, 'title':'Base Data'},
-            {'url':customer_url + '/documents', 'title':_('Documents')},
+            {'url':customer_url + '/applications', 'title':_('My Applications')},
+            {'url':customer_url + '/documents', 'title':_('My Documents')},
             {'url':customer_url + '/history', 'title':_('History')},
             ]
@@ -148,6 +152,13 @@
     text = _(u'Base Data')
 
+
+class CustomerManageApplicationsLink(CustomerManageLink):
+    grok.order(3)
+    link = 'applications'
+    text = _(u'Applications')
+
+
 class CustomerManageDocumentsLink(CustomerManageLink):
-    grok.order(3)
+    grok.order(4)
     link = 'documents'
     text = _(u'Documents')
@@ -298,5 +309,5 @@
 
 
-class PDFOverviewActionButton(ManageActionButton):
+class PDFDocumentOverviewActionButton(ManageActionButton):
     grok.order(2)
     grok.context(ICustomerDocumentsContainer)
@@ -351,5 +362,6 @@
     icon = 'actionicon_view.png'
 
-class PDFSlipActionButton(ManageActionButton):
+
+class PDFDocumentSlipActionButton(ManageActionButton):
     grok.order(3)
     grok.context(ICustomerDocument)
@@ -359,2 +371,77 @@
     text = _('Download document slip')
     target = 'document_slip.pdf'
+
+# Viewlets for customer applications
+
+class AddApplicationActionButton(AddActionButton):
+    grok.order(1)
+    grok.context(IApplicationsContainer)
+    grok.view(ApplicationsManageFormPage)
+    grok.require('waeup.editApplications')
+    text = _('Add application')
+    target = 'addapp'
+
+
+class PDFApplicationOverviewActionButton(ManageActionButton):
+    grok.order(2)
+    grok.context(IApplicationsContainer)
+    grok.view(ApplicationsManageFormPage)
+    grok.require('waeup.viewCustomer')
+    icon = 'actionicon_pdf.png'
+    text = _('Download applications overview')
+    target = 'overview_slip.pdf'
+
+
+class ApplicationManageActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IApplication)
+    grok.view(ApplicationDisplayFormPage)
+    grok.require('waeup.manageCustomer')
+    text = _('Manage')
+    target = 'manage'
+
+
+class ApplicationEditActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IApplication)
+    grok.view(ApplicationDisplayFormPage)
+    grok.require('waeup.handleCustomer')
+    text = _('Edit')
+    target = 'edit'
+
+    @property
+    def target_url(self):
+        if not self.context.is_editable:
+            return ''
+        return self.view.url(self.view.context, self.target)
+
+
+class ApplicationTrigTransActionButton(ManageActionButton):
+    grok.order(2)
+    grok.context(IApplication)
+    grok.view(ApplicationDisplayFormPage)
+    grok.require('waeup.triggerTransition')
+    icon = 'actionicon_trigtrans.png'
+    text = _(u'Transition')
+    target = 'trigtrans'
+
+
+class ApplicationViewActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IApplication)
+    grok.view(ApplicationManageFormPage)
+    grok.require('waeup.handleCustomer')
+    text = _('View')
+    target = 'index'
+    icon = 'actionicon_view.png'
+
+
+class PDFApplicationSlipActionButton(ManageActionButton):
+    grok.order(3)
+    grok.context(IApplication)
+    grok.view(ApplicationDisplayFormPage)
+    grok.require('waeup.viewCustomer')
+    icon = 'actionicon_pdf.png'
+    text = _('Download application slip')
+    target = 'application_slip.pdf'
+
