Index: main/waeup.fceokene/trunk/src/waeup/fceokene/students/browser.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/students/browser.py	(revision 14590)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/students/browser.py	(revision 14591)
@@ -24,5 +24,6 @@
 from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
 from waeup.kofa.students.browser import (
-    StartClearancePage, BedTicketAddPage, ExportPDFAdmissionSlip)
+    StartClearancePage, BedTicketAddPage,
+    ExportPDFAdmissionSlip, StudyLevelDisplayFormPage)
 from kofacustom.nigeria.students.browser import (
     NigeriaOnlinePaymentDisplayFormPage,
@@ -30,9 +31,11 @@
     NigeriaExportPDFPaymentSlip,
     NigeriaStudentClearanceEditFormPage,
-    NigeriaExportPDFClearanceSlip
+    NigeriaExportPDFClearanceSlip,
+    NigeriaExportPDFCourseRegistrationSlip
     )
 
 from waeup.fceokene.students.interfaces import (
-    ICustomStudentOnlinePayment, ICustomUGStudentClearance)
+    ICustomStudentOnlinePayment, ICustomUGStudentClearance,
+    ICustomStudentStudyLevel)
 
 class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip):
@@ -141,2 +144,17 @@
     notice = ''
     with_ac = False
+
+class CustomStudyLevelDisplayFormPage(StudyLevelDisplayFormPage):
+    """ Page to display student study levels
+    """
+    grok.context(ICustomStudentStudyLevel)
+    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit('level')
+    form_fields[
+        'validation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
+
+class CustomExportPDFCourseRegistrationSlip(
+    NigeriaExportPDFCourseRegistrationSlip):
+    """Deliver a PDF slip of the context.
+    """
+    grok.context(ICustomStudentStudyLevel)
+    form_fields = grok.AutoFields(ICustomStudentStudyLevel).omit('level')
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/students/interfaces.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/students/interfaces.py	(revision 14590)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/students/interfaces.py	(revision 14591)
@@ -250,4 +250,19 @@
     """
 
+    total_credits_s1 = schema.Int(
+        title = _(u'1st Semester Credits'),
+        required = False,
+        )
+
+    total_credits_s2 = schema.Int(
+        title = _(u'2nd Semester Credits'),
+        required = False,
+        )
+
+    total_credits = schema.Int(
+        title = _(u'Total Credits'),
+        required = False,
+        )
+
 class ICustomStudentOnlinePayment(ICustomOnlinePayment):
     """A student payment via payment gateways.
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/students/studylevel.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/students/studylevel.py	(revision 14590)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/students/studylevel.py	(revision 14591)
@@ -52,6 +52,23 @@
     grok.provides(ICustomStudentStudyLevel)
 
+    @property
+    def total_credits_s1(self):
+        total = 0
+        for ticket in self.values():
+            if ticket.semester == 1 and not ticket.outstanding:
+                total += ticket.credits
+        return total
+
+    @property
+    def total_credits_s2(self):
+        total = 0
+        for ticket in self.values():
+            if ticket.semester == 2 and not ticket.outstanding:
+                total += ticket.credits
+        return total
+
 CustomStudentStudyLevel = attrs_to_fields(
-    CustomStudentStudyLevel, omit=['total_credits', 'gpa'])
+    CustomStudentStudyLevel, omit=[
+    'total_credits', 'total_credits_s1', 'total_credits_s2', 'gpa'])
 
 class CustomStudentStudyLevelFactory(StudentStudyLevelFactory):
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_browser.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_browser.py	(revision 14590)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_browser.py	(revision 14591)
@@ -29,4 +29,5 @@
 from waeup.kofa.students.accommodation import BedTicket
 from waeup.kofa.testing import FunctionalTestCase
+from waeup.kofa.browser.tests.test_pdf import samples_dir
 from waeup.kofa.interfaces import (
     IExtFileStore, IFileStoreNameChooser)
@@ -416,2 +417,23 @@
                            self.browser.contents)
         return
+
+    def test_student_course_registration(self):
+        IWorkflowState(self.student).setState('school fee paid')
+        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()
+        # Students can't open the customized pdf course registration slip
+        self.browser.open(
+            self.student_path + '/studycourse/100/course_registration_slip.pdf')
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
+        path = os.path.join(samples_dir(), 'course_registration_slip.pdf')
+        open(path, 'wb').write(self.browser.contents)
+        print "Sample PDF course_registration_slip.pdf written to %s" % path
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_utils.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_utils.py	(revision 14590)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/students/tests/test_utils.py	(revision 14591)
@@ -31,15 +31,25 @@
         return
 
-    def test_maxCreditsExceeded(self):
+    def test_warnCreditsOOR(self):
         students_utils = getUtility(IStudentsUtils)
         studylevel = grok.Container()
-        studylevel.total_credits = 40
+        studylevel.total_credits_s1 = 17
+        studylevel.total_credits_s2 = 17
         course = grok.Model()
-        course.credits = 18
+        course.credits = 7
+        course.semester = 1
         warning = students_utils.warnCreditsOOR(studylevel, course)
         self.assertEqual(warning, None)
-        course.credits = 19
+        course.credits = 8
         warning = students_utils.warnCreditsOOR(studylevel, course)
-        self.assertEqual(warning, 'Maximum credits exceeded.')
+        self.assertEqual(warning, 'Maximum credits in 1st semester exceeded.')
+        course.semester = 2
+        warning = students_utils.warnCreditsOOR(studylevel, course)
+        self.assertEqual(warning, 'Maximum credits in 2nd semester exceeded.')
+        warning = students_utils.warnCreditsOOR(studylevel)
+        self.assertEqual(warning, 'Minimum credits in 1st semester not reached.')
+        studylevel.total_credits_s1 = 18
+        warning = students_utils.warnCreditsOOR(studylevel)
+        self.assertEqual(warning, 'Minimum credits in 2nd semester not reached.')
         return
 
Index: main/waeup.fceokene/trunk/src/waeup/fceokene/students/utils.py
===================================================================
--- main/waeup.fceokene/trunk/src/waeup/fceokene/students/utils.py	(revision 14590)
+++ main/waeup.fceokene/trunk/src/waeup/fceokene/students/utils.py	(revision 14591)
@@ -362,11 +362,24 @@
 
     def warnCreditsOOR(self, studylevel, course=None):
-        """Return message if credits are out of range. In the base
-        package only maximum credits is set.
-        """
-        if course and studylevel.total_credits + course.credits > 58:
-            return _('Maximum credits exceeded.')
-        elif studylevel.total_credits > 58:
-            return _('Maximum credits exceeded.')
+        """Return message if credits are out of range. 
+        """
+        # adding a course ticket
+        if course:
+            if course.semester == 1:
+                if studylevel.total_credits_s1 + course.credits > 24:
+                    return _('Maximum credits in 1st semester exceeded.')
+            if course.semester == 2:
+                if studylevel.total_credits_s2 + course.credits > 24:
+                    return _('Maximum credits in 2nd semester exceeded.')
+        # registering course list
+        else:
+            if studylevel.total_credits_s1 > 24:
+                return _('Maximum credits in 1st semester exceeded.')
+            if studylevel.total_credits_s1 < 18:
+                return _('Minimum credits in 1st semester not reached.')
+            if studylevel.total_credits_s2 > 24:
+                return _('Maximum credits in 2nd semester exceeded.')
+            if studylevel.total_credits_s2 < 18:
+                return _('Minimum credits in 2nd semester not reached.')
         return
 
