Index: /main/waeup.kofa/trunk/CHANGES.txt
===================================================================
--- /main/waeup.kofa/trunk/CHANGES.txt	(revision 16186)
+++ /main/waeup.kofa/trunk/CHANGES.txt	(revision 16187)
@@ -4,4 +4,6 @@
 1.6.1.dev0 (unreleased)
 =======================
+
+* Implement temporarily clearance.
 
 * `reg_number` is no longer a required field in `IApplicantBaseData`.
Index: /main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py	(revision 16186)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/browser/tests/test_browser.py	(revision 16187)
@@ -442,5 +442,5 @@
             'phone,reg_number,sex,student_id,suspended,suspended_comment,'
             'password,state,history,certcode,is_postgrad,current_level,'
-            'current_session\r\n')
+            'current_session,entry_session\r\n')
         logfile = os.path.join(
             self.app['datacenter'].storage, 'logs', 'datacenter.log')
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 16186)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 16187)
@@ -858,4 +858,63 @@
         return
 
+class StudentTempClearancePage(KofaEditFormPage):
+    """ Temporarily clearance by clearance officers.
+    """
+    grok.context(IStudent)
+    grok.name('temp_clearance')
+    label = _('Clear student temporarily')
+    grok.require('waeup.clearStudent')
+    form_fields = grok.AutoFields(
+        IUGStudentClearance).select('officer_comment')
+
+    def update(self):
+        cdm = getUtility(IStudentsUtils).clearance_disabled_message(
+            self.context)
+        if cdm:
+            self.flash(cdm, type="warning")
+            self.redirect(self.url(self.context,'view_clearance'))
+            return
+        return super(StudentTempClearancePage, self).update()
+
+    @action(_('Save comment and clear student temporarily now'), style='primary')
+    def temp_clear(self, **data):
+        if self.context.state == REQUESTED:
+            if self.context.officer_comment \
+                and self.context.officer_comment.startswith('Temporarily cleared'):
+                self.flash(
+                    _('Not allowed: student has already been '
+                      'temporarily cleared.'),
+                    type="warning")
+                self.redirect(self.url(self.context,'view_clearance'))
+                return
+            if not data['officer_comment']:
+                self.flash(_('Please write a comment.'), type="warning")
+                self.redirect(self.url(self.context,'view_clearance'))
+                return
+            message = _('Student has been temporarily cleared.')
+            self.flash(message)
+        else:
+            self.flash(_('Student is in wrong state.'), type="warning")
+            self.redirect(self.url(self.context,'view_clearance'))
+            return
+        user = get_current_principal()
+        if user is None:
+            usertitle = 'system'
+        else:
+            usertitle = getattr(user, 'public_name', None)
+            if not usertitle:
+                usertitle = user.title
+        comment = data['officer_comment']
+        data['officer_comment'] = translate(
+            _('Temporarily cleared by ${a}. Officers comment:\n${b}',
+            mapping = {'a':usertitle, 'b':comment}))
+        self.applyData(self.context, **data)
+        self.context.writeLogMessage(
+            self, 'comment: %s' % comment.replace('\n', '<br>'))
+        args = {'subject':'You have been temporarily cleared.', 'body':comment}
+        self.redirect(self.url(self.context) +
+            '/contactstudent?%s' % urlencode(args))
+        return
+
 class StudentRejectClearancePage(KofaEditFormPage):
     """ Reject clearance by clearance officers.
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 16186)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 16187)
@@ -1677,4 +1677,56 @@
         IWorkflowInfo(self.student).fireTransition('clear')
         self.assertEqual(self.student.officer_comment, None)
+        return
+
+    def test_handle_temp_clearance_by_co(self):
+        self.app['configuration']['2004'].clearance_enabled = True
+        self.init_clearance_officer()
+        # Hide real name.
+        self.app['users']['mrclear'].public_name = 'My Public Name'
+        IWorkflowInfo(self.student).fireTransition('request_clearance')
+        #notify(LocalRoleSetEvent(
+        #    self.department, 'waeup.local.ClearanceOfficer', 'mrclear',
+        #    granted=True))
+        # CO can view the student ...
+        self.browser.open(self.clearance_path)
+        self.browser.getLink("Clear student temporarily").click()
+        self.assertEqual(
+            self.browser.url, self.student_path + '/temp_clearance')
+        # Type comment why.
+        self.browser.getControl(name="form.officer_comment").value = (
+            'Dear Student,\n'
+            'Your birth cert is missing.')
+        self.browser.getControl(
+            'Save comment and clear student temporarily now').click()
+        self.assertTrue('Student has been temporarily cleared.'
+            in self.browser.contents)
+        url = ('http://localhost/app/students/K1000000/'
+              'contactstudent?body=Dear+Student%2C%0AYour+birth+cert+is+missing.'
+              '&subject=You+have+been+temporarily+cleared.')
+        # CO does now see the prefilled contact form and can send a message.
+        self.assertEqual(self.browser.url, url)
+        self.assertTrue('clearance requested' in self.browser.contents)
+        self.assertTrue('name="form.subject" size="20" type="text" '
+            'value="You have been temporarily cleared."'
+            in self.browser.contents)
+        self.assertTrue('name="form.body" rows="10" >Dear Student,'
+            in self.browser.contents)
+        self.browser.getControl("Send message now").click()
+        self.assertTrue('Your message has been sent' in self.browser.contents)
+        # The comment has been stored ...
+        self.assertEqual(self.student.officer_comment,
+            'Temporarily cleared by My Public Name. Officers comment:\n'
+            'Dear Student,\nYour birth cert is missing.')
+        # ... and logged.
+        logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'students.log')
+        logcontent = open(logfile).read()
+        self.assertTrue(
+            'INFO - mrclear - students.browser.StudentTempClearancePage - '
+            'K1000000 - comment: Dear Student,<br>Your birth cert is '
+            'missing.\n' in logcontent)
+        # CO can view the student bus no longer see the temp clearance button ...
+        self.browser.open(self.clearance_path)
+        self.assertFalse('Clear student temporarily' in self.browser.contents)
         return
 
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py	(revision 16186)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py	(revision 16187)
@@ -306,7 +306,29 @@
         return self.view.url(self.view.context, self.target)
 
+class StudentTemporarilyClearActionButton(ManageActionButton):
+    grok.order(3)
+    grok.context(IStudent)
+    grok.view(StudentClearanceDisplayFormPage)
+    grok.require('waeup.clearStudent')
+    text = _('Clear student temporarily')
+    target = 'temp_clearance'
+    icon = 'actionicon_accept.png'
+
+    @property
+    def target_url(self):
+        cdm = getUtility(
+            IStudentsUtils).clearance_disabled_message(self.context)
+        if cdm:
+            return ''
+        if self.context.officer_comment \
+            and self.context.officer_comment.startswith('Temporarily cleared'):
+            return ''
+        if self.context.state != REQUESTED:
+            return ''
+        return self.view.url(self.view.context, self.target)
+
 
 class StudentRejectClearanceActionButton(ManageActionButton):
-    grok.order(3)
+    grok.order(4)
     grok.context(IStudent)
     grok.view(StudentClearanceDisplayFormPage)
@@ -328,5 +350,5 @@
 
 class ClearanceSlipActionButton(ManageActionButton):
-    grok.order(4)
+    grok.order(5)
     grok.context(IStudent)
     grok.view(StudentClearanceDisplayFormPage)
