Index: main/waeup.ikoba/trunk/src/waeup/ikoba/browser/templates/loginpage.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/browser/templates/loginpage.pt	(revision 12038)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/browser/templates/loginpage.pt	(revision 12039)
@@ -11,5 +11,5 @@
     <div class="col-sm-10">
       <input name="form.password" type="password" class="form-control" id="password">
-      <font  i18n:translate="" color="red"> Notice: User names, Ids and passwords are case sensitive.</font>
+      <font  i18n:translate="" color="red"> Notice: User names, ids and passwords are case sensitive.</font>
     </div>
   </div>
@@ -22,13 +22,17 @@
   </p>
   <p i18n:translate="login_trouble2" tal:condition="python:False">
-    You don't have an account because you are a new customer, or your customer record has just been created?
+    You don't have an account because you are a new customer, or your customer record has been created for you?
     Acquire a Password Activation Code (PWD) and inititialize your customer account
     <strong><a href ="setpassword"> here</a></strong>.
   </p>
   <p i18n:translate="login_trouble4">
-    You don't have an account because you are a new customer, or your customer record has just been created?
+    You don't have an account because you are a new customer?
+    Create your customer account <strong><a href="createaccount"> here</a></strong>.
+  </p>
+  <p i18n:translate="login_trouble5">
+    You don't have an account because you are a new customer and your customer record has been created for you?
     Inititialize your customer account <strong><a href="requestpw"> here</a></strong>.
   </p>
-  <p i18n:translate="login_trouble3"> Or simply forgot your customer id password? Then request a new password
+  <p i18n:translate="login_trouble3"> Or simply forgot your id or password? Then request a new password
     <strong><a href="changepw"> here</a></strong>.
   </p>
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12038)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12039)
@@ -47,5 +47,5 @@
 from waeup.ikoba.customers.interfaces import (
     ICustomer, ICustomersContainer, ICustomerRequestPW, ICustomersUtils,
-    ICustomerDocument, ICustomerDocumentsContainer
+    ICustomerDocument, ICustomerDocumentsContainer, ICustomerCreate
     )
 from waeup.ikoba.customers.catalog import search
@@ -467,11 +467,10 @@
 
 class CustomerRequestPasswordPage(IkobaAddFormPage):
-    """Captcha'd registration page for applicants.
+    """Captcha'd password request page for customers.
     """
     grok.name('requestpw')
     grok.require('waeup.Anonymous')
     grok.template('requestpw')
-    form_fields = grok.AutoFields(ICustomerRequestPW).select(
-        'firstname','number','email')
+    form_fields = grok.AutoFields(ICustomerRequestPW)
     label = _('Request password for first-time login')
 
@@ -484,5 +483,5 @@
 
     def _redirect(self, email, password, customer_id):
-        # Forward only email to landing page in base package.
+        # Forward only email address to landing page in base package.
         self.redirect(self.url(self.context, 'requestpw_complete',
             data=dict(email=email)))
@@ -554,4 +553,63 @@
 
 
+class CustomerCreateAccountPage(IkobaAddFormPage):
+    """Captcha'd account creation page for customers.
+    """
+    grok.name('createaccount')
+    grok.require('waeup.Anonymous')
+    grok.template('createaccount')
+    form_fields = grok.AutoFields(ICustomerCreate)
+    label = _('Create customer account')
+
+    def update(self):
+        # Handle captcha
+        self.captcha = getUtility(ICaptchaManager).getCaptcha()
+        self.captcha_result = self.captcha.verify(self.request)
+        self.captcha_code = self.captcha.display(self.captcha_result.error_code)
+        return
+
+    def _redirect(self, email, password, customer_id):
+        # Forward only email address to landing page in base package.
+        self.redirect(self.url(self.context, 'requestpw_complete',
+            data=dict(email=email)))
+        return
+
+    @action(_('Send login credentials to email address'), style='primary')
+    def create_account(self, **data):
+        if not self.captcha_result.is_valid:
+            # Captcha will display error messages automatically.
+            # No need to flash something.
+            return
+        customer = createObject(u'waeup.Customer')
+        customer.firstname = data.get('firstname','')
+        customer.middlename = data.get('middlename','')
+        customer.lastname = data.get('lastname','')
+        customer.email = data.get('email','')
+        self.context['customers'].addCustomer(customer)
+        ikoba_utils = getUtility(IIkobaUtils)
+        password = ikoba_utils.genPassword()
+        mandate = PasswordMandate()
+        mandate.params['password'] = password
+        mandate.params['user'] = customer
+        site = grok.getSite()
+        site['mandates'].addMandate(mandate)
+        # Send email with credentials
+        args = {'mandate_id':mandate.mandate_id}
+        mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
+        url_info = u'Confirmation link: %s' % mandate_url
+        msg = _('You have successfully created a customer account for the')
+        if ikoba_utils.sendCredentials(IUserAccount(customer),
+            password, url_info, msg):
+            email_sent = customer.email
+        else:
+            email_sent = None
+        self._redirect(email=email_sent, password=password,
+            customer_id=customer.customer_id)
+        ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
+        self.context.logger.info(
+            '%s - %s - %s' % (ob_class, customer.customer_id, email_sent))
+        return
+
+
 class CustomerRequestPasswordEmailSent(IkobaPage):
     """Landing page after successful password request.
@@ -561,5 +619,5 @@
     grok.require('waeup.Public')
     grok.template('requestpwmailsent')
-    label = _('Your password request was successful.')
+    label = _('Your request was successful.')
 
     def update(self, email=None, customer_id=None, password=None):
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/changepassword.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/changepassword.pt	(revision 12038)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/changepassword.pt	(revision 12039)
@@ -21,4 +21,5 @@
     </tbody>
   </table>
+  <br />
 
   <div tal:condition="view/availableActions">
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/createaccount.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/createaccount.pt	(revision 12039)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/createaccount.pt	(revision 12039)
@@ -0,0 +1,29 @@
+<form action="." tal:attributes="action request/URL" method="post"
+    i18n:domain="waeup.ikoba" enctype="multipart/form-data">
+
+  <table class="form-table">
+    <tbody>
+      <tal:widgets content="structure provider:widgets" />
+      <tr tal:condition="view/captcha_code">
+        <td i18n:translate="">
+          Please solve the captcha<br />to prevent misuse of this service:
+        </td>
+        <td>
+          <div tal:content="structure view/captcha_code"></div>
+        </td>
+      </tr>
+
+    </tbody>
+  </table>
+  <p i18n:translate="">
+    A customer record will be created and
+    your login credentials will be sent to the email address given above.
+    To be able to proceed you must provide a valid email address!
+  </p>
+  <br />
+  <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/requestpw.pt
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/requestpw.pt	(revision 12038)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser_templates/requestpw.pt	(revision 12039)
@@ -21,4 +21,5 @@
     To be able to proceed you must provide a valid email address!
   </p>
+  <br />
   <div tal:condition="view/availableActions">
     <input tal:repeat="action view/actions"
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12038)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12039)
@@ -205,6 +205,6 @@
 
 
-class ICustomerRequestPW(ICustomer):
-    """Representation of an customer for first-time password request.
+class ICustomerRequestPW(IIkobaObject):
+    """Representation of a customer for first-time password request.
 
     This interface is used when customers use the requestpw page to
@@ -228,4 +228,32 @@
 
 
+class ICustomerCreate(IIkobaObject):
+    """Representation of an customer for account creation.
+
+    This interface is used when customers use the createaccount page.
+    """
+
+    firstname = schema.TextLine(
+        title = _(u'First Name'),
+        required = True,
+        )
+
+    middlename = schema.TextLine(
+        title = _(u'Middle Name'),
+        required = False,
+        )
+
+    lastname = schema.TextLine(
+        title = _(u'Last Name (Surname)'),
+        required = True,
+        )
+
+    email = schema.ASCIILine(
+        title = _(u'Email Address'),
+        required = True,
+        constraint=validate_email,
+        )
+
+
 # Customer document interfaces
 
Index: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py
===================================================================
--- main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12038)
+++ main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py	(revision 12039)
@@ -703,5 +703,5 @@
         self.browser.getControl("Send login credentials").click()
         # Yeah, we succeded ...
-        self.assertTrue('Your password request was successful.'
+        self.assertTrue('Your request was successful.'
             in self.browser.contents)
         # ... and  customer can be found in the catalog via the email address
