Index: main/waeup.kofa/trunk/CHANGES.txt
===================================================================
--- main/waeup.kofa/trunk/CHANGES.txt	(revision 15985)
+++ main/waeup.kofa/trunk/CHANGES.txt	(revision 15986)
@@ -4,4 +4,9 @@
 1.6.1.dev0 (unreleased)
 =======================
+
+* When adding course tickets, check if course has already been
+  passed at previous level.
+
+* Add `StudentTrimmedPaymentExporter` (requested by Uniben).
 
 * Add `AccommodationDisplayFormPage`.
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15985)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py	(revision 15986)
@@ -155,4 +155,8 @@
         view.flash(warning, type="warning")
         return False
+    warning = students_utils.warnCourseAlreadyPassed(view.context, course)
+    if warning:
+        view.flash(warning, type="warning")
+        return False
     try:
         view.context.addCourseTicket(ticket, course)
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 15985)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py	(revision 15986)
@@ -2834,4 +2834,49 @@
         return
 
+    def test_student_course_already_passed(self):
+        IWorkflowState(self.student).setState('school fee paid')
+        self.student['studycourse'].current_level = 100
+        self.browser.open(self.login_path)
+        self.browser.getControl(name="form.login").value = self.student_id
+        self.browser.getControl(name="form.password").value = 'spwd'
+        self.browser.getControl("Login").click()
+        # Now students can add the current study level
+        self.browser.getLink("Study Course").click()
+        self.browser.getLink("Add course list").click()
+        self.assertMatches('...Add current level 100 (Year 1)...',
+                           self.browser.contents)
+        self.browser.getControl("Create course list now").click()
+        # A level with one course ticket was created
+        self.assertEqual(self.student['studycourse']['100'].number_of_tickets, 1)
+        # We set the score above the passmark
+        self.student['studycourse']['100'][
+            'COURSE1'].score = self.student['studycourse']['100'][
+                'COURSE1'].passmark + 1
+        # We add a second level
+        self.student['studycourse'].current_level = 200
+        self.browser.getLink("Study Course").click()
+        self.browser.getLink("Add course list").click()
+        self.assertMatches('...Add current level 200 (Year 2)...',
+                           self.browser.contents)
+        self.browser.getControl("Create course list now").click()
+        self.browser.getLink("200").click()
+        self.browser.getLink("Edit course list").click()
+        self.browser.getLink("here").click()
+        self.browser.getControl(name="form.course").value = ['COURSE1']
+        self.browser.getControl("Add course ticket").click()
+        self.assertTrue(
+            'Course has already been passed at previous level'
+            in self.browser.contents)
+        self.assertEqual(self.student['studycourse']['200'].number_of_tickets, 0)
+        # We set the score below the passmark
+        self.student['studycourse']['100'][
+            'COURSE1'].score = self.student['studycourse']['100'][
+                'COURSE1'].passmark - 1
+        self.browser.getControl("Add course ticket").click()
+        self.assertTrue(
+            'Successfully added COURSE1' in self.browser.contents)
+        self.assertEqual(self.student['studycourse']['200'].number_of_tickets, 1)
+        return
+
     def test_student_course_registration_outstanding(self):
         self.course = createObject('waeup.Course')
Index: main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py	(revision 15985)
+++ main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py	(revision 15986)
@@ -732,4 +732,15 @@
         return
 
+    def warnCourseAlreadyPassed(self, studylevel, course):
+        """Return message if course has already been passed at
+        previous levels.
+        """
+        for slevel in studylevel.__parent__.values():
+            for cticket in slevel.values():
+                if cticket.code == course.code \
+                    and cticket.total_score >= cticket.passmark:
+                    return _('Course has already been passed at previous level.')
+        return False
+
     def getBedCoordinates(self, bedticket):
         """Return descriptive bed coordinates.
