Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 9137)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 9138)
@@ -52,4 +52,5 @@
     IUGStudentClearance,IPGStudentClearance,
     IStudentPersonal, IStudentBase, IStudentStudyCourse,
+    IStudentStudyCourseTransfer,
     IStudentAccommodation, IStudentStudyLevel,
     ICourseTicket, ICourseTicketAdd, IStudentPaymentsContainer,
@@ -775,4 +776,33 @@
                 mapping = {'a':', '.join(deleted)}))
         self.redirect(self.url(self.context, u'@@manage')+'?tab2')
+        return
+
+class StudentTransferFormPage(KofaAddFormPage):
+    """Page to transfer the student.
+    """
+    grok.context(IStudent)
+    grok.name('transfer')
+    grok.require('waeup.manageStudent')
+    label = _('Transfer student')
+    form_fields = grok.AutoFields(IStudentStudyCourseTransfer).omit(
+        'entry_mode', 'entry_session')
+    pnav = 4
+
+    def update(self):
+        super(StudentTransferFormPage, self).update()
+        warning.need()
+        return
+
+    @jsaction(_('Transfer'))
+    def transferStudent(self, **data):
+        error = self.context.transfer(**data)
+        if error == -1:
+            self.flash(_('Current level does not match certificate levels.'))
+        elif error == -2:
+            self.flash(_('Former study course record incomplete.'))
+        elif error == -3:
+            self.flash(_('Maximum number of transfers exceeded.'))
+        else:
+            self.flash(_('Successfully transferred.'))
         return
 
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py	(revision 9137)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py	(revision 9138)
@@ -372,4 +372,28 @@
         )
 
+class IStudentStudyCourseTransfer(IStudentStudyCourse):
+    """An student transfers.
+
+    """
+
+    certificate = schema.Choice(
+        title = _(u'Certificate'),
+        source = CertificateSource(),
+        required = True,
+        )
+
+    current_level = schema.Choice(
+        title = _(u'Current Level'),
+        source = StudyLevelSource(),
+        required = True,
+        readonly = False,
+        )
+
+
+IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
+    'certificate'].order
+IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
+    'current_level'].order
+
 class IStudentVerdictUpdate(IKofaObject):
     """A interface for verdict imports.
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/student.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/student.py	(revision 9137)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/student.py	(revision 9138)
@@ -160,9 +160,12 @@
             return -1
         old = self['studycourse']
+        if getattr(old, 'entry_session', None) is None or\
+            getattr(old, 'certificate', None) is None:
+            return -2
         studycourse.entry_session = old.entry_session
         # Students can be transferred only two times.
         if 'studycourse_1' in self.keys():
             if 'studycourse_2' in self.keys():
-                return -2
+                return -3
             self['studycourse_2'] = old
         else:
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 9137)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 9138)
@@ -1948,4 +1948,28 @@
                         'K1000000 - account activated' in logcontent)
 
+    def test_student_transfer(self):
+        # Add second certificate
+        self.certificate2 = createObject('waeup.Certificate')
+        self.certificate2.code = u'CERT2'
+        self.certificate2.study_mode = 'ug_ft'
+        self.certificate2.start_level = 999
+        self.certificate2.end_level = 999
+        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
+            self.certificate2)
+
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.student_path)
+        self.browser.getLink("Transfer").click()
+        self.browser.getControl(name="form.certificate").value = ['CERT2']
+        self.browser.getControl(name="form.current_session").value = ['2011']
+        self.browser.getControl(name="form.current_level").value = ['200']
+        self.browser.getControl("Transfer").click()
+        self.assertTrue(
+            'Current level does not match certificate levels'
+            in self.browser.contents)
+        self.browser.getControl(name="form.current_level").value = ['999']
+        self.browser.getControl("Transfer").click()
+        self.assertTrue('Successfully transferred' in self.browser.contents)
+
 class StudentRequestPWTests(StudentsFullSetup):
     # Tests for student registration
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_student.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_student.py	(revision 9137)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_student.py	(revision 9138)
@@ -308,5 +308,5 @@
         error = self.student.transfer(self.certificate2,
             current_session=2013)
-        self.assertTrue(error == -2)
+        self.assertTrue(error == -3)
         self.assertEqual([i for i in self.student.keys()],
             [u'accommodation', u'payments', u'studycourse',
Index: /main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py	(revision 9137)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py	(revision 9138)
@@ -1,3 +1,3 @@
-## $Id$
+3## $Id$
 ##
 ## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
@@ -166,6 +166,15 @@
     target = 'manage_base'
 
+class StudentTransfernButton(ManageActionButton):
+    grok.order(5)
+    grok.context(IStudent)
+    grok.view(StudentBaseDisplayFormPage)
+    grok.require('waeup.manageStudent')
+    text = _('Transfer student')
+    target = 'transfer'
+    icon = 'actionicon_redo.png'
+
 class StudentDeactivateActionButton(ManageActionButton):
-    grok.order(5)
+    grok.order(6)
     grok.context(IStudent)
     grok.view(StudentBaseDisplayFormPage)
@@ -182,5 +191,5 @@
 
 class StudentActivateActionButton(ManageActionButton):
-    grok.order(5)
+    grok.order(6)
     grok.context(IStudent)
     grok.view(StudentBaseDisplayFormPage)
@@ -285,4 +294,10 @@
     target = 'manage'
 
+    @property
+    def target_url(self):
+        if self.context.is_current:
+            return self.view.url(self.view.context, self.target)
+        return False
+
 class StudyLevelManageActionButton(ManageActionButton):
     grok.order(1)
@@ -292,4 +307,11 @@
     text = _('Manage')
     target = 'manage'
+
+    @property
+    def target_url(self):
+        is_current = self.context.__parent__.is_current
+        if not is_current:
+            return ''
+        return self.view.url(self.view.context, self.target)
 
 class StudentValidateCoursesActionButton(ManageActionButton):
@@ -304,6 +326,8 @@
     @property
     def target_url(self):
+        is_current = self.context.__parent__.is_current
         if self.context.student.state != REGISTERED or \
-            str(self.context.__parent__.current_level) != self.context.__name__:
+            str(self.context.__parent__.current_level) != self.context.__name__ or\
+            not is_current:
             return ''
         return self.view.url(self.view.context, self.target)
@@ -320,6 +344,8 @@
     @property
     def target_url(self):
+        is_current = self.context.__parent__.is_current
         if self.context.student.state not in (VALIDATED, REGISTERED) or \
-            str(self.context.__parent__.current_level) != self.context.__name__:
+            str(self.context.__parent__.current_level) != self.context.__name__ or\
+            not is_current:
             return ''
         return self.view.url(self.view.context, self.target)
@@ -334,4 +360,11 @@
     target = 'course_registration.pdf'
 
+    @property
+    def target_url(self):
+        is_current = self.context.__parent__.is_current
+        if not is_current:
+            return ''
+        return self.view.url(self.view.context, self.target)
+
 class CourseTicketManageActionButton(ManageActionButton):
     grok.order(1)
@@ -479,5 +512,5 @@
     @property
     def target_url(self):
-        if self.context.next_session_allowed:
+        if self.context.next_session_allowed and self.context.is_current:
             return self.view.url(self.view.context, self.target)
         return False
@@ -497,5 +530,6 @@
         condition2 = str(student['studycourse'].current_level) in \
             self.view.context.keys()
-        if condition1 or condition2:
+        condition3 = not self.context.is_current
+        if condition1 or condition2 or condition3:
             return ''
         return self.view.url(self.view.context, self.target)
@@ -515,5 +549,6 @@
         condition2 = student[
             'studycourse'].current_level != self.view.context.level
-        if condition1 or condition2:
+        is_current = self.context.__parent__.is_current
+        if condition1 or condition2 or not is_current:
             return ''
         return self.view.url(self.view.context, self.target)
