Index: main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/interswitch/tests.py
===================================================================
--- main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/interswitch/tests.py	(revision 10674)
+++ main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/interswitch/tests.py	(revision 10675)
@@ -28,4 +28,5 @@
 from waeup.kofa.configuration import SessionConfiguration
 from waeup.kwarapoly.testing import FunctionalLayer
+from waeup.kwarapoly.students.payments import CustomStudentOnlinePayment
 
 # Also run tests that send requests to external servers?
@@ -76,4 +77,6 @@
         notify(grok.ObjectModifiedEvent(self.student))
 
+
+    def test_schoolfee_ticket_creation(self):
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
         self.browser.open(self.payments_path)
@@ -82,8 +85,24 @@
         self.browser.getControl(name="form.p_category").value = ['schoolfee']
         self.browser.getControl("Create ticket").click()
+        self.assertMatches('...Book and pay for accommodation first...',
+                           self.browser.contents)
+        # We add a fake maint. payment ticket to meet the condition
+        maint_payment = CustomStudentOnlinePayment()
+        self.student['payments']['any_key'] = maint_payment
+        maint_payment.p_category = 'hostel_maintenance'
+        maint_payment.p_state = 'unpaid'
+        maint_payment.p_session = 2004
+        self.browser.getControl(name="form.p_category").value = ['schoolfee']
+        self.browser.getControl("Create ticket").click()
+        self.assertMatches('...Book and pay for accommodation first...',
+                           self.browser.contents)
+        # Ticket must be paid
+        maint_payment.p_state = 'paid'
+        self.browser.getControl(name="form.p_category").value = ['schoolfee']
+        self.browser.getControl("Create ticket").click()
         self.assertMatches('...ticket created...',
                            self.browser.contents)
         ctrl = self.browser.getControl(name='val_id')
-        self.value = ctrl.options[0]
+        self.value = ctrl.options[1]
         self.browser.getLink(self.value).click()
         self.assertMatches('...Amount Authorized...',
@@ -107,4 +126,26 @@
 
     def test_interswitch_form(self):
+
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open(self.payments_path)
+        # In KwaraPoly only returning students can create school fee payment
+        # without haveing paid accommodation fee
+        IWorkflowState(self.student).setState('returning')
+        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('...ticket created...', self.browser.contents)
+        ctrl = self.browser.getControl(name='val_id')
+        self.value = ctrl.options[0]
+        self.browser.getLink(self.value).click()
+        self.assertMatches('...Amount Authorized...', self.browser.contents)
+        self.assertMatches(
+            '...<span>29500.0</span>...',
+            self.browser.contents)
+        self.payment_url = self.browser.url
+
         # Manager can access InterswitchForm
         self.assertEqual(self.student['payments'][self.value].provider_amt, 0.0)
@@ -119,8 +160,8 @@
                            self.browser.contents)
         self.assertTrue(
-            '<input type="hidden" name="amount" value="3940000.0" />' in
-            self.browser.contents)
-        self.assertTrue(
-            'item_name="School Fee" item_amt="3610000" bank_id="120" acct_num="1771180233"' in
+            '<input type="hidden" name="amount" value="2950000.0" />' in
+            self.browser.contents)
+        self.assertTrue(
+            'item_name="School Fee" item_amt="2620000" bank_id="120" acct_num="1771180233"' in
             self.browser.contents)
         self.assertTrue(
Index: main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/tests/test_browser.py
===================================================================
--- main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/tests/test_browser.py	(revision 10674)
+++ main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/tests/test_browser.py	(revision 10675)
@@ -104,4 +104,16 @@
         self.browser.getControl(name="form.p_category").value = ['schoolfee']
         self.browser.getControl("Create ticket").click()
+
+        self.assertMatches('...Book and pay for accommodation first...',
+                           self.browser.contents)
+
+        # In KwaraPoly only returning students can create school fee payment
+        # without haveing paid accommodation fee
+        IWorkflowState(self.student).setState('returning')
+        configuration = createObject('waeup.SessionConfiguration')
+        configuration.academic_session = 2005
+        self.app['configuration'].addSessionConfiguration(configuration)
+        self.browser.getControl(name="form.p_category").value = ['schoolfee']
+        self.browser.getControl("Create ticket").click()
         self.assertMatches('...ticket created...',
                            self.browser.contents)
@@ -155,19 +167,4 @@
         self.browser.open(self.payments_path + '/addop')
         self.browser.getControl(name="form.p_category").value = ['schoolfee']
-        self.browser.getControl("Create ticket").click()
-        self.assertMatches('...ticket created...',
-                           self.browser.contents)
-        # In state returning we can add a new school fee ticket since
-        # p_session and p_level is different
-        IWorkflowState(self.student).setState('returning')
-        self.browser.open(self.payments_path + '/addop')
-        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.assertTrue('Session configuration object is not available.'
-            in self.browser.contents)
-        configuration = createObject('waeup.SessionConfiguration')
-        configuration.academic_session = 2005
-        self.app['configuration'].addSessionConfiguration(configuration)
         self.browser.getControl("Create ticket").click()
         self.assertMatches('...ticket created...',
@@ -222,4 +219,14 @@
         self.assertEqual(pt_ft(self.student), 'ft')
 
+        error, payment = utils.setPaymentDetails('schoolfee',self.student)
+        self.assertEqual(error,
+            'Book and pay for accommodation first before making'
+            ' school fee payments.')
+        # We add a fake maint. payment ticket to meet the condition
+        maint_payment = createObject('waeup.StudentOnlinePayment')
+        self.student['payments']['any_key'] = maint_payment
+        maint_payment.p_category = 'hostel_maintenance'
+        maint_payment.p_state = 'paid'
+        maint_payment.p_session = 2004
         error, payment = utils.setPaymentDetails('schoolfee',self.student)
         self.assertEqual(payment.p_level, 100)
Index: main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/utils.py
===================================================================
--- main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/utils.py	(revision 10674)
+++ main/waeup.kwarapoly/trunk/src/waeup/kwarapoly/students/utils.py	(revision 10675)
@@ -20,4 +20,5 @@
 from time import time
 from zope.component import createObject, getUtility
+from zope.catalog.interfaces import ICatalog
 from waeup.kofa.interfaces import CLEARED, RETURNING, PAID
 from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
@@ -25,4 +26,5 @@
 from waeup.kofa.interfaces import CLEARED, RETURNING, IKofaUtils
 from waeup.kofa.fees import FeeTable
+from waeup.kofa.hostels.hostel import NOT_OCCUPIED
 from waeup.kwarapoly.interfaces import MessageFactory as _
 
@@ -124,4 +126,29 @@
         new_session = student['studycourse'].current_session + 1
         return new_session, new_level
+
+    def _maintPaymentMade(self, student, session):
+        if len(student['payments']):
+            for ticket in student['payments'].values():
+                if ticket.p_category == 'hostel_maintenance' and \
+                    ticket.p_session == session and ticket.p_state == 'paid':
+                        return True
+        return False
+
+    def _bedAvailable(self, student):
+        acc_details  = self.getAccommodationDetails(student)
+        cat = getUtility(ICatalog, name='beds_catalog')
+        entries = cat.searchResults(
+            owner=(student.student_id,student.student_id))
+        if len(entries):
+            # Bed has already been booked.
+            return True
+        entries = cat.searchResults(
+            bed_type=(acc_details['bt'],acc_details['bt']))
+        available_beds = [
+            entry for entry in entries if entry.owner == NOT_OCCUPIED]
+        if available_beds:
+            # Bed has not yet been booked but beds are available.
+            return True
+        return False
 
     def setPaymentDetails(self, category, student,
@@ -170,4 +197,10 @@
                 if academic_session == None:
                     return _(u'Session configuration object is not available.'), None
+            if student.state == CLEARED:
+                # Fresh students must have booked and paid for accommodation.
+                if self._bedAvailable(student):
+                    if not self._maintPaymentMade(student, p_session):
+                        return _('Book and pay for accommodation first '
+                                 'before making school fee payments.'), None
             if student.state in (RETURNING, CLEARED):
                 if p_level in PAYMENT_LEVELS:
