Index: /main/waeup.uniben/trunk/src/waeup/uniben/interswitch/tests.py
===================================================================
--- /main/waeup.uniben/trunk/src/waeup/uniben/interswitch/tests.py	(revision 9519)
+++ /main/waeup.uniben/trunk/src/waeup/uniben/interswitch/tests.py	(revision 9520)
@@ -97,5 +97,7 @@
             self.browser.contents)
 
-        # Create school fee ticket for returning students
+        # Create school fee ticket for returning students. Payment is made
+        # for next session.
+        current_payment_key = self.student['payments'].keys()[0]
         self.certificate.study_mode = u'ug_pt'
         IWorkflowState(self.student).setState('returning')
@@ -103,4 +105,13 @@
         configuration.academic_session = 2005
         self.app['configuration'].addSessionConfiguration(configuration)
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(name="form.p_category").value = ['schoolfee']
+        self.browser.getControl("Create ticket").click()
+        # Next session payment can't be made ...
+        self.assertMatches(
+            '...You have not yet paid your current/active session...',
+            self.browser.contents)
+        # current session payment must be approved first.
+        self.student['payments'][current_payment_key].approve()
         self.browser.open(self.payments_path + '/addop')
         self.browser.getControl(name="form.p_category").value = ['schoolfee']
Index: /main/waeup.uniben/trunk/src/waeup/uniben/students/tests/test_browser.py
===================================================================
--- /main/waeup.uniben/trunk/src/waeup/uniben/students/tests/test_browser.py	(revision 9519)
+++ /main/waeup.uniben/trunk/src/waeup/uniben/students/tests/test_browser.py	(revision 9520)
@@ -214,5 +214,5 @@
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
         self.browser.open(self.payments_path)
-        self.browser.getControl("Add online payment ticket").click()
+        self.browser.getLink("Add current session payment ticket").click()
         self.browser.getControl("Create ticket").click()
         self.assertMatches('...Amount could not be determined...',
@@ -248,4 +248,5 @@
         self.assertMatches('...ticket created...',
                            self.browser.contents)
+        schoolfee_ticket = self.student['payments'].values()[0]
         self.browser.open(self.payments_path + '/addop')
         self.browser.getControl(name="form.p_category").value = ['gown']
@@ -286,10 +287,17 @@
         self.browser.getControl(name="form.p_category").value = ['schoolfee']
         self.browser.getControl("Create ticket").click()
+        # Uups, we forgot to add a session configuration for next session
         self.assertMatches('...Session configuration object is not...',
                            self.browser.contents)
-        # Uups, we forgot to add a session configuration for next session
         configuration = createObject('waeup.SessionConfiguration')
         configuration.academic_session = 2005
         self.app['configuration'].addSessionConfiguration(configuration)
+        self.browser.open(self.payments_path + '/addop')
+        self.browser.getControl(name="form.p_category").value = ['schoolfee']
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...You have not yet paid your current/active session...',
+                           self.browser.contents)
+        # Ok, let's pay the first schoolfee ticket.
+        schoolfee_ticket.approve()
         self.browser.open(self.payments_path + '/addop')
         self.browser.getControl(name="form.p_category").value = ['schoolfee']
@@ -309,5 +317,5 @@
         del self.app['configuration']['2004']
         self.browser.open(self.payments_path)
-        self.browser.getControl("Add online payment ticket").click()
+        self.browser.getLink("Add current session payment ticket").click()
         self.browser.getControl("Create ticket").click()
         self.assertMatches('...Session configuration object is not...',
@@ -375,4 +383,5 @@
             self.student, None, None)
         self.assertEqual(payment, None)
+        # Student is in state 'created' and can thus not pay.
         self.assertTrue(u'Amount could not be determined.' in error)
 
@@ -383,9 +392,9 @@
         self.assertTrue(u'The previous session must not fall below' in error)
         error, payment = utils.setPaymentDetails('schoolfee',
-            self.student, 2004, 300)
+            self.student, 2005, 300)
         self.assertEqual(payment, None)
         self.assertTrue(u'This is not a previous session' in error)
 
-        # Previous session payment; fresh and returning
+        # Previous session schoolfee payment; fresh and returning
         # are distinguished by their entry_level
         error, payment = utils.setPaymentDetails('schoolfee',
@@ -402,5 +411,5 @@
         self.assertFalse(payment.p_current)
 
-        # Current payment; fresh and returning
+        # Current schoolfee payment; fresh and returning
         # are distinguished by their state
         IWorkflowState(self.student).setState('cleared')
@@ -426,4 +435,16 @@
         error, payment = utils.setPaymentDetails('schoolfee',
             self.student, None, None)
+        self.assertTrue(
+            u'You have not yet paid your current/active session.' in error)
+        # Ok, that means we have to add paid payment ticket first.
+        payment = createObject('waeup.StudentOnlinePayment')
+        payment.p_category = u'schoolfee'
+        payment.p_session = self.student.current_session
+        payment.p_item = u'My Certificate'
+        payment.p_id = u'anyid'
+        payment.p_state = u'paid'
+        self.student['payments']['anykey'] = payment
+        error, payment = utils.setPaymentDetails('schoolfee',
+            self.student, None, None)
         self.assertEqual(payment.p_level, 200)
         self.assertEqual(payment.p_session, 2005)
@@ -431,4 +452,6 @@
         self.assertEqual(payment.p_item, u'CERT1')
         self.assertEqual(error, None)
+
+        # Staff members pay less.
         self.student.is_staff = True
         error, payment = utils.setPaymentDetails('schoolfee',
@@ -440,4 +463,5 @@
         self.assertEqual(error, None)
 
+        # Foreigners pay more.
         IWorkflowState(self.student).setState('cleared')
         self.student.is_staff = False
@@ -451,8 +475,6 @@
         self.assertEqual(payment.p_item, u'CERT1')
         self.assertEqual(error, None)
-
         IWorkflowState(self.student).setState('returning')
         self.student.is_staff = False
-        self.student.nationality = u'DE'
         self.certificate.school_fee_4 = 20000.0
         error, payment = utils.setPaymentDetails(
@@ -467,9 +489,16 @@
         # if they are ug or pg students.
         IWorkflowState(self.student).setState('school fee paid')
-        self.certificate.study_mode = 'special_pg_pt'
         self.student.is_staff = False
         self.student.nationality = u'NG'
         self.certificate.school_fee_2 = 10000.0
-
+        error, payment = utils.setPaymentDetails(
+            'schoolfee', self.student, None, None)
+        self.assertEqual(payment.p_level, None)
+        self.assertEqual(payment.p_session, 2005)
+        self.assertEqual(payment.amount_auth, 10088.0)
+        self.assertEqual(payment.p_item, u'CERT1')
+        self.assertEqual(error, None)
+        IWorkflowState(self.student).setState('courses registered')
+        self.certificate.study_mode = 'special_pg_pt'
         error, payment = utils.setPaymentDetails(
             'schoolfee', self.student, None, None)
@@ -479,14 +508,4 @@
         self.assertEqual(payment.p_item, u'CERT1')
         self.assertEqual(error, None)
-
-        IWorkflowState(self.student).setState('courses registered')
-        error, payment = utils.setPaymentDetails(
-            'schoolfee', self.student, None, None)
-        self.assertEqual(payment.p_level, None)
-        self.assertEqual(payment.p_session, 2005)
-        self.assertEqual(payment.amount_auth, 10000.0)
-        self.assertEqual(payment.p_item, u'CERT1')
-        self.assertEqual(error, None)
-
         IWorkflowState(self.student).setState('courses validated')
         error, payment = utils.setPaymentDetails(
Index: /main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py
===================================================================
--- /main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py	(revision 9519)
+++ /main/waeup.uniben/trunk/src/waeup/uniben/students/utils.py	(revision 9520)
@@ -53,4 +53,13 @@
         return new_session, new_level
 
+    def _paymentMade(self, student, session):
+        if len(student['payments']):
+            for ticket in student['payments'].values():
+                if ticket.p_state == 'paid' and \
+                    ticket.p_category == 'schoolfee' and \
+                    ticket.p_session == session:
+                    return True
+        return False
+
     def setPaymentDetails(self, category, student,
             previous_session, previous_level):
@@ -59,9 +68,17 @@
 
         """
-        details = {}
         p_item = u''
         amount = 0.0
-        error = u''
         if previous_session:
+            if previous_session < student['studycourse'].entry_session:
+                return _('The previous session must not fall below '
+                         'your entry session.'), None
+            if category == 'schoolfee':
+                # School fee is always paid for the following session
+                if previous_session > student['studycourse'].current_session:
+                    return _('This is not a previous session.'), None
+            else:
+                if previous_session > student['studycourse'].current_session - 1:
+                    return _('This is not a previous session.'), None
             p_session = previous_session
             p_level = previous_level
@@ -71,8 +88,6 @@
             p_level = student['studycourse'].current_level
             p_current = True
-        session = str(p_session)
-        try:
-            academic_session = grok.getSite()['configuration'][session]
-        except KeyError:
+        academic_session = self._getSessionConfiguration(p_session)
+        if academic_session == None:
             return _(u'Session configuration object is not available.'), None
         # Determine fee.
@@ -105,9 +120,7 @@
                 return _('Study course data are incomplete.'), None
             if previous_session:
-                if previous_session < student['studycourse'].entry_session:
-                    return _('The previous session must not fall below '
-                             'your entry session.'), None
-                if previous_session > student['studycourse'].current_session - 1:
-                    return _('This is not a previous session.'), None
+                # Students can pay for previous sessions in all workflow states.
+                # Fresh students are excluded by the update method of the
+                # PreviousPaymentAddFormPage.
                 if previous_session == student['studycourse'].entry_session:
                     if student.is_foreigner:
@@ -127,14 +140,18 @@
                         amount = getattr(certificate, 'school_fee_1', 0.0)
                 elif student.state in (PAID, REGISTERED, VALIDATED):
-                    # Students are either postgraduate or are paying in advance.
-                    # Both are paying for next session.
                     p_session += 1
                     # We don't know which level the student is paying for.
                     p_level = None
-                    try:
-                        academic_session = grok.getSite()[
-                            'configuration'][str(p_session)]
-                    except KeyError:
+                    academic_session = self._getSessionConfiguration(p_session)
+                    if academic_session == None:
                         return _(u'Session configuration object is not available.'), None
+                    # Students are only allowed to pay for the next session
+                    # if current session payment
+                    # has really been made, i.e. payment object exists.
+                    if not self._paymentMade(
+                        student, student.current_session):
+                        return _('You have not yet paid your current/active' +
+                                 ' session. Please use the previous session' +
+                                 ' payment form first.'), None
                     if student.is_foreigner:
                         amount = getattr(certificate, 'school_fee_4', 0.0)
@@ -146,9 +163,15 @@
                     # has paid for.
                     p_session, p_level = self.getReturningData(student)
-                    try:
-                        academic_session = grok.getSite()[
-                            'configuration'][str(p_session)]
-                    except KeyError:
+                    academic_session = self._getSessionConfiguration(p_session)
+                    if academic_session == None:
                         return _(u'Session configuration object is not available.'), None
+                    # Students are only allowed to pay for the next session
+                    # if current session payment has really been made,
+                    # i.e. payment object exists and is paid.
+                    if not self._paymentMade(
+                        student, student.current_session):
+                        return _('You have not yet paid your current/active' +
+                                 ' session. Please use the previous session' +
+                                 ' payment form first.'), None
                     if student.is_foreigner:
                         amount = getattr(certificate, 'school_fee_4', 0.0)
@@ -159,6 +182,5 @@
                 amount /= 2
         if amount in (0.0, None):
-            return _('Amount could not be determined.' +
-                     ' Would you like to pay for a previous session?'), None
+            return _('Amount could not be determined.'), None
         # Add session specific penalty fee.
         if category == 'schoolfee' and student.is_postgrad:
@@ -173,6 +195,5 @@
                ticket.p_item == p_item and \
                ticket.p_session == p_session:
-                  return _('This type of payment has already been made.' +
-                           ' Would you like to pay for a previous session?'), None
+                  return _('This type of payment has already been made.'), None
         payment = createObject(u'waeup.StudentOnlinePayment')
         timestamp = ("%d" % int(time()*10000))[1:]
