Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 7132)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 7133)
@@ -22,5 +22,5 @@
 from zope.event import notify
 from zope.catalog.interfaces import ICatalog
-from zope.component import queryUtility
+from zope.component import queryUtility, getUtility
 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
 from zope.component import createObject
@@ -34,5 +34,5 @@
 from waeup.sirp.browser.viewlets import (
     ManageActionButton, PrimaryNavTab, AddActionButton)
-from waeup.sirp.interfaces import IWAeUPObject, IUserAccount
+from waeup.sirp.interfaces import IWAeUPObject, IUserAccount, IExtFileStore
 from waeup.sirp.widgets.datewidget import (
     FriendlyDateWidget, FriendlyDateDisplayWidget,
@@ -62,5 +62,5 @@
     return
 
-# Save function used for save methods in manager pages
+# Save function used for save methods in pages
 def msave(view, **data):
     form = view.request.form
@@ -74,4 +74,9 @@
     if fields_string:
         write_log_message(view, 'saved: %s' % fields_string)
+    return
+
+def emitLockMessage(view):
+    view.flash('The requested form is locked (read-only).')
+    view.redirect(view.url(view.context))
     return
 
@@ -364,11 +369,11 @@
     grok.require('waeup.manageStudents')
     text = 'Manage'
-    target = 'edit_base'
+    target = 'manage_base'
 
 class StudentBaseManageFormPage(WAeUPEditFormPage):
-    """ View to edit student base data
-    """
-    grok.context(IStudent)
-    grok.name('edit_base')
+    """ View to manage student base data
+    """
+    grok.context(IStudent)
+    grok.name('manage_base')
     grok.require('waeup.manageStudents')
     form_fields = grok.AutoFields(IStudentBase).omit('student_id')
@@ -409,4 +414,5 @@
                 write_log_message(self, 'password changed')
 
+        # The following is now done by contextual_reg_num_source validation
         #self.reg_number = form.get('form.reg_number', None)
         #if self.reg_number:
@@ -1448,6 +1454,14 @@
 # Pages for students only
 
+class StudentBaseActionButton(ManageActionButton):
+    grok.order(1)
+    grok.context(IStudent)
+    grok.view(StudentBaseDisplayFormPage)
+    grok.require('waeup.handleStudent')
+    text = 'Edit base data'
+    target = 'edit_base'
+
 class StudentPasswordActionButton(ManageActionButton):
-    grok.order(1)
+    grok.order(2)
     grok.context(IStudent)
     grok.view(StudentBaseDisplayFormPage)
@@ -1458,5 +1472,5 @@
 
 class StudentPassportActionButton(ManageActionButton):
-    grok.order(1)
+    grok.order(3)
     grok.context(IStudent)
     grok.view(StudentBaseDisplayFormPage)
@@ -1465,4 +1479,28 @@
     text = 'Change portrait'
     target = 'change_portrait'
+
+    @property
+    def target_url(self):
+        if self.context.state != 'admitted':
+            return ''
+        return self.view.url(self.view.context, self.target)
+
+class StudentBaseEditFormPage(WAeUPEditFormPage):
+    """ View to edit student base data
+    """
+    grok.context(IStudent)
+    grok.name('edit_base')
+    grok.require('waeup.handleStudent')
+    form_fields = grok.AutoFields(IStudentBase).select(
+        'email', 'phone')
+    #grok.template('basemanagepage')
+    label = 'Edit base data'
+    title = 'Base Data'
+    pnav = 4
+
+    @grok.action('Save')
+    def save(self, **data):
+        msave(self, **data)
+        return
 
 class StudentPasswordSetting(grok.Adapter):
@@ -1543,4 +1581,11 @@
     pnav = 4
 
+    def update(self):
+        if self.context.getStudent().state != 'admitted':
+            emitLockMessage(self)
+            return
+        super(StudentFilesUploadPage, self).update()
+        return
+
 class StudentClearanceStartActionButton(ManageActionButton):
     grok.order(1)
@@ -1570,8 +1615,29 @@
     buttonname = 'Start clearance now'
 
+    @property
+    def all_required_fields_filled(self):
+        if self.context.email and self.context.phone:
+            return True
+        return False
+
+    @property
+    def portrait_uploaded(self):
+        store = getUtility(IExtFileStore)
+        if store.getFileByContext(self.context, attr=u'passport.jpg'):
+            return True
+        return False
+
     def update(self, SUBMIT=None):
         if not self.context.state == 'admitted':
             self.flash("Wrong state.")
             self.redirect(self.url(self.context))
+            return
+        if not self.portrait_uploaded:
+            self.flash("No portrait uploaded.")
+            self.redirect(self.url(self.context, 'change_portrait'))
+            return
+        if not self.all_required_fields_filled:
+            self.flash("Not all required fields filled.")
+            self.redirect(self.url(self.context, 'edit_base'))
             return
         self.ac_series = self.request.form.get('ac_series', None)
@@ -1630,14 +1696,8 @@
     form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
 
-    def emitLockMessage(self):
-        self.flash('The requested form is locked (read-only).')
-        self.redirect(self.url(self.context))
-        return
-
     def update(self):
         if self.context.clearance_locked:
-            self.emitLockMessage()
-            return
-        datepicker.need()
+            emitLockMessage(self)
+            return
         return super(StudentClearanceEditFormPage, self).update()
 
@@ -1793,12 +1853,7 @@
         return 'Add current level %s' % title
 
-    def emitLockMessage(self):
-        self.flash('The requested form is locked (read-only).')
-        self.redirect(self.url(self.context))
-        return
-
     def update(self):
         if self.context.getStudent().state != 'school fee paid':
-            self.emitLockMessage()
+            emitLockMessage(self)
             return
         super(AddStudyLevelFormPage, self).update()
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/interfaces.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/interfaces.py	(revision 7132)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/interfaces.py	(revision 7133)
@@ -1,4 +1,5 @@
 ##
 ## interfaces.py
+import re
 from datetime import datetime
 from zope.interface import Attribute, invariant
@@ -14,4 +15,15 @@
 from waeup.sirp.payments.interfaces import IPaymentsContainer, IOnlinePayment
 
+# Define a valiation method for email addresses
+class NotAnEmailAddress(schema.ValidationError):
+    __doc__ = u"Invalid email address"
+
+check_email = re.compile(
+    r"[a-zA-Z0-9._%-]+@([a-zA-Z0-9-]+.)*[a-zA-Z]{2,4}").match
+def validate_email(value):
+    if not check_email(value):
+        raise NotAnEmailAddress(value)
+    return True
+
 class IStudentsContainer(IWAeUPObject):
     """A students container contains university students.
@@ -139,4 +151,15 @@
         required = False,
         readonly = True,
+        )
+
+    email = schema.ASCIILine(
+        title = u'Email',
+        required = False,
+        constraint=validate_email,
+        )
+    phone = schema.Int(
+        title = u'Phone',
+        description = u'Enter phone number with country code and without spaces.',
+        required = False,
         )
 
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_student_data.csv
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_student_data.csv	(revision 7132)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_student_data.csv	(revision 7133)
@@ -1,4 +1,4 @@
-firstname,lastname,fullname,reg_number,date_of_birth,matric_number
-Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000
-Aaren,Finau,Aaren Finau,2,1990-01-03,100001
-Aaren,Berson,Aaren Berson,3,1990-01-04,100002
+firstname,lastname,fullname,reg_number,date_of_birth,matric_number,email,phone
+Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000,aa@aa.ng,1234
+Aaren,Finau,Aaren Finau,2,1990-01-03,100001,aa@aa.ng,1234
+Aaren,Berson,Aaren Berson,3,1990-01-04,100002,aa@aa.ng,1234
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py	(revision 7132)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py	(revision 7133)
@@ -91,4 +91,6 @@
         student.matric_number = u'234'
         student.sex = u'm'
+        student.email = 'aa@aa.ng'
+        student.phone = 1234
         self.app['students'].addStudent(student)
         self.student_id = student.student_id
@@ -104,5 +106,5 @@
         self.add_student_path = self.container_path + '/addstudent'
         self.student_path = self.container_path + '/' + self.student_id
-        self.manage_student_path = self.student_path + '/edit_base'
+        self.manage_student_path = self.student_path + '/manage_base'
         self.clearance_student_path = self.student_path + '/view_clearance'
         self.personal_student_path = self.student_path + '/view_personal'
@@ -584,8 +586,8 @@
         # Prepare a csv file for students
         open('students.csv', 'wb').write(
-"""firstname,lastname,fullname,reg_number,date_of_birth,matric_number
-Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000
-Claus,Finau,Claus Finau,2,1990-01-03,100001
-Brit,Berson,Brit Berson,3,1990-01-04,100001
+"""firstname,lastname,fullname,reg_number,date_of_birth,matric_number,email,phone
+Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000,aa@aa.ng,1234
+Claus,Finau,Claus Finau,2,1990-01-03,100001,aa@aa.ng,1234
+Brit,Berson,Brit Berson,3,1990-01-04,100001,aa@aa.ng,1234
 """)
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
@@ -757,4 +759,11 @@
         self.browser.getLink("Clearance Data").click()
         self.browser.getLink("Start clearance").click()
+        self.student.email = None
+        # Uups, we forgot to fill the email fields
+        self.browser.getControl("Start clearance").click()
+        self.assertMatches('...Not all required fields filled...',
+                           self.browser.contents)
+        self.student.email = 'aa@aa.ng'
+        self.browser.open(self.student_path + '/start_clearance')
         self.browser.getControl(name="ac_series").value = '3'
         self.browser.getControl(name="ac_number").value = '4444444'
@@ -923,14 +932,4 @@
         ac = self.app['accesscodes']['CLR-0'][pin]
         ac.owner = self.student_id
-        # The new CLR-0 pin can be used for starting clearance
-        IWorkflowInfo(self.student).fireTransition('admit')
-        self.browser.open(self.student_path + '/start_clearance')
-        parts = pin.split('-')[1:]
-        clrseries, clrnumber = parts
-        self.browser.getControl(name="ac_series").value = clrseries
-        self.browser.getControl(name="ac_number").value = clrnumber
-        self.browser.getControl("Start clearance now").click()
-        self.assertMatches('...Clearance process has been started...',
-                           self.browser.contents)
         return
 
@@ -975,5 +974,17 @@
 
         # The new CLR-0 pin can be used for starting clearance
+        # but they have to upload a passport picture first
+        # which is only possible in state admitted
+        self.browser.open(self.student_path + '/change_portrait')
+        self.assertMatches('...form is locked...',
+                          self.browser.contents)
         IWorkflowInfo(self.student).fireTransition('admit')
+        self.browser.open(self.student_path + '/change_portrait')
+        pseudo_image = StringIO('I pretend to be a graphics file')
+        ctrl = self.browser.getControl(name='passportuploadedit')
+        file_ctrl = ctrl.mech_control
+        file_ctrl.add_file(pseudo_image, filename='my_photo.jpg')
+        self.browser.getControl(
+            name='upload_passportuploadedit').click()
         self.browser.open(self.student_path + '/start_clearance')
         parts = pin.split('-')[1:]
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/workflow.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/workflow.py	(revision 7132)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/workflow.py	(revision 7133)
@@ -176,4 +176,6 @@
 def handle_student_transition_event(obj, event):
     """Append message to student history and log file when transition happened.
+
+      Lock and unlock clearance form.
     """
     msg = '%s' % event.transition.user_data['msg']
