Index: /main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_utils.py
===================================================================
--- /main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_utils.py	(revision 16135)
+++ /main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_utils.py	(revision 16136)
@@ -39,2 +39,76 @@
         self.assertEqual(msg, None)
         return
+
+    def test_set_payment_details(self):
+        self.app['configuration']['2004'].book = 150.0
+        self.app['configuration']['2004'].develop = 90.0
+        self.app['configuration']['2004'].registration = 180.0
+        self.app['configuration']['2004'].municipal_fresh = 280.0
+        self.app['configuration']['2004'].pcf = 380.0
+        self.student['studycourse'].certificate.school_fee_2 = 6666.0
+        IWorkflowState(self.student).setState('cleared')
+        utils = getUtility(IStudentsUtils)
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Registration Fee, Book Deposit, Development Fee, Municipal Fee, '
+            'Parents Consultative Forum (PCF) Fee must be paid before Tution Fee.')
+        reg_payment = createObject('waeup.StudentOnlinePayment')
+        reg_payment.p_category = u'registration'
+        reg_payment.p_id = u'anyid'
+        reg_payment.p_state = u'paid'
+        reg_payment.p_session = 2004
+        self.student['payments']['anykey'] = reg_payment
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Book Deposit, Development Fee, Municipal Fee, Parents Consultative '
+            'Forum (PCF) Fee must be paid before Tution Fee.')
+        IWorkflowState(self.student).setState('returning')
+        configuration = createObject('waeup.SessionConfiguration')
+        configuration.academic_session = 2005
+        self.app['configuration'].addSessionConfiguration(configuration)
+        self.app['configuration']['2005'].registration = 170.0
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Registration Fee, Book Deposit, Development Fee, Municipal Fee, '
+            'Parents Consultative Forum (PCF) Fee must be paid before Tution Fee.')
+        reg_payment.p_session = 2005
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Book Deposit, Development Fee, Municipal Fee, Parents Consultative '
+            'Forum (PCF) Fee must be paid before Tution Fee.')
+        pcf_payment = createObject('waeup.StudentOnlinePayment')
+        pcf_payment.p_category = u'parentsconsult'
+        pcf_payment.p_id = u'anyid'
+        pcf_payment.p_state = u'paid'
+        pcf_payment.p_session = 2005
+        self.student['payments']['anykey2'] = pcf_payment
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Book Deposit, Development Fee, Municipal Fee must be paid before Tution Fee.')
+        munic_payment = createObject('waeup.StudentOnlinePayment')
+        munic_payment.p_category = u'municipal_fresh'
+        munic_payment.p_id = u'anyid'
+        munic_payment.p_state = u'paid'
+        munic_payment.p_session = 2005
+        self.student['payments']['anykey3'] = munic_payment
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Book Deposit, Development Fee must be paid before Tution Fee.')
+        book_payment = createObject('waeup.StudentOnlinePayment')
+        book_payment.p_category = u'book'
+        book_payment.p_id = u'anyid'
+        book_payment.p_state = u'paid'
+        book_payment.p_session = 2005
+        self.student['payments']['anykey4'] = book_payment
+        develop_payment = createObject('waeup.StudentOnlinePayment')
+        develop_payment.p_category = u'develop'
+        develop_payment.p_id = u'anyid'
+        develop_payment.p_state = u'paid'
+        develop_payment.p_session = 2005
+        self.student['payments']['anykey5'] = develop_payment
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error, None)
+        self.assertEqual(payment.p_level, 200)
+        self.assertEqual(payment.p_session, 2005)
+        self.assertEqual(payment.amount_auth, 6666.0)
+        return
Index: /main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/utils.py
===================================================================
--- /main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/utils.py	(revision 16135)
+++ /main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/utils.py	(revision 16136)
@@ -18,4 +18,5 @@
 import grok
 from time import time
+from copy import deepcopy
 from zope.component import createObject, getUtility
 from waeup.kofa.interfaces import (IKofaUtils,
@@ -30,5 +31,5 @@
     """
 
-    # refix
+    # prefix
     STUDENT_ID_PREFIX = u'I'
 
@@ -41,5 +42,14 @@
     #: A tuple containing the names of registration states in which changing of
     #: passport pictures is allowed.
+
     PORTRAIT_CHANGE_STATES = (ADMITTED, CLEARANCE,)
+
+    REQUIRED_PAYMENTS = {
+        'registration': 'Registration Fee',
+        'book': 'Book Deposit',
+        'develop': 'Development Fee',
+        'parentsconsult': 'Parents Consultative Forum (PCF) Fee',
+        'municipal': 'Municipal Fee',
+        }
 
     def warnCreditsOOR(self, studylevel, course=None):
@@ -53,6 +63,20 @@
         return
 
+    def _requiredPaymentsMissing(self, student, session):
+        cats_missing = deepcopy(self.REQUIRED_PAYMENTS)
+        if len(student['payments']):
+            for category in self.REQUIRED_PAYMENTS.keys():
+                for ticket in student['payments'].values():
+                    if ticket.p_state == 'paid' and \
+                        ticket.p_category.startswith(category) and \
+                        ticket.p_session == session:
+                        del cats_missing[category]
+        if cats_missing:
+            return "%s must be paid before Tution Fee." % ', '.join(
+                cats_missing.values())
+        return
+
     def setPaymentDetails(self, category, student,
-            previous_session, previous_level, combi=[]):
+            previous_session=None, previous_level=None, combi=[]):
         """Create a payment ticket and set the payment data of a
         student for the payment category specified.
@@ -78,4 +102,11 @@
             p_level = student['studycourse'].current_level
             p_current = True
+            if category in self.REQUIRED_PAYMENTS.keys() + [
+                'schoolfee','schoolfee40','secondinstal'] \
+                and student.state == RETURNING:
+                # In case of school fee or required sundry fee payments the
+                # payment session is always next session if students are in
+                # state returning.
+                p_session, p_level = self.getReturningData(student)
         academic_session = self._getSessionConfiguration(p_session)
         if academic_session == None:
@@ -84,4 +115,7 @@
         if category in ('schoolfee', 'schoolfee40',
                         'secondinstal'):
+            rpm = self._requiredPaymentsMissing(student, p_session)
+            if rpm:
+                return rpm, None
             try:
                 certificate = student['studycourse'].certificate
@@ -111,14 +145,4 @@
                         amount = getattr(certificate, 'school_fee_1', 0.0)
                     elif student.state == RETURNING:
-                        # In case of returning school fee payment the
-                        # payment session and level contain the values of
-                        # the session the student has paid for. Payment
-                        # session is always next session.
-                        p_session, p_level = self.getReturningData(student)
-                        academic_session = self._getSessionConfiguration(p_session)
-                        if academic_session == None:
-                            return _(
-                                u'Session configuration object is not available.'
-                                ), None
                         amount = getattr(certificate, 'school_fee_2', 0.0)
                     elif student.is_postgrad and student.state == PAID:
