Index: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/permissions.py
===================================================================
--- main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/permissions.py	(revision 15858)
+++ main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/permissions.py	(revision 15859)
@@ -19,4 +19,15 @@
 from waeup.kofa.permissions import CCOfficer
 
+class ClearLibrary(grok.Permission):
+    grok.name('waeup.switchLibraryAccess')
+
+class LibraryClearanceOfficer(grok.Role):
+    """Library Clearance Officers can enable library id card slips.
+    """
+    grok.name('waeup.LibraryClearanceOfficer')
+    grok.title(u'Library Clearance Officer')
+    grok.permissions('waeup.showStudents',
+                     'waeup.viewAcademics',
+                     'waeup.switchLibraryAccess')
 
 class CRPUOfficer(CCOfficer):
Index: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/browser.py
===================================================================
--- main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/browser.py	(revision 15858)
+++ main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/browser.py	(revision 15859)
@@ -49,5 +49,5 @@
 from kofacustom.iuokada.students.interfaces import (
     ICustomStudentOnlinePayment, ICustomStudentStudyCourse,
-    ICustomStudentStudyLevel, ICustomStudentBase)
+    ICustomStudentStudyLevel, ICustomStudentBase, ICustomStudent)
 from kofacustom.iuokada.interfaces import MessageFactory as _
 
@@ -123,2 +123,84 @@
     def render(self):
         return
+
+class SwitchLibraryAccessView(UtilityView, grok.View):
+    """ Switch the library attribute
+    """
+    grok.context(ICustomStudent)
+    grok.name('switch_library_access')
+    grok.require('waeup.switchLibraryAccess')
+
+    def update(self):
+        if self.context.library:
+            self.context.library = False
+            self.context.writeLogMessage(self, 'library access disabled')
+            self.flash(_('Library access disabled'))
+        else:
+            self.context.library = True
+            self.context.writeLogMessage(self, 'library access enabled')
+            self.flash(_('Library access enabled'))
+        self.redirect(self.url(self.context))
+        return
+
+    def render(self):
+        return
+
+class ExportLibIdCard(UtilityView, grok.View):
+    """Deliver an id card for the library.
+    """
+    grok.context(ICustomStudent)
+    grok.name('lib_idcard.pdf')
+    grok.require('waeup.viewStudent')
+    prefix = 'form'
+
+    label = u"Library Clearance"
+
+    omit_fields = (
+        'suspended', 'email', 'phone',
+        'adm_code', 'suspended_comment',
+        'date_of_birth',
+        'current_mode', 'certificate',
+        'entry_session',
+        'flash_notice')
+
+    form_fields = []
+
+    def _sigsInFooter(self):
+        isStudent = getattr(
+            self.request.principal, 'user_type', None) == 'student'
+        if isStudent:
+            return ''
+        return (_("Date, Reader's Signature"),
+                _("Date, Circulation Librarian's Signature"),
+                )
+
+    def update(self):
+        if not self.context.library:
+            self.flash(_('Forbidden!'), type="danger")
+            self.redirect(self.url(self.context))
+        return
+
+    @property
+    def note(self):
+        return """
+<br /><br /><br /><br /><font size='12'>
+This is to certify that the bearer whose photograph and other details appear
+ overleaf is a registered user of the <b>University Library</b>.
+ The card is not transferable. A replacement fee is charged for a loss,
+ mutilation or otherwise. If found, please, return to the University Library,
+ Igbinedion University, Okada.
+</font>
+
+"""
+        return
+
+    def render(self):
+        studentview = StudentBasePDFFormPage(self.context.student,
+            self.request, self.omit_fields)
+        students_utils = getUtility(IStudentsUtils)
+        return students_utils.renderPDF(
+            self, 'lib_idcard',
+            self.context.student, studentview,
+            omit_fields=self.omit_fields,
+            sigs_in_footer=self._sigsInFooter(),
+            note=self.note)
Index: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/interfaces.py
===================================================================
--- main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/interfaces.py	(revision 15858)
+++ main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/interfaces.py	(revision 15859)
@@ -38,4 +38,10 @@
         required = False,
         constraint=validate_email,
+        )
+
+    library = schema.Bool(
+        title = _(u'Library Id Card'),
+        default = False,
+        required = False,
         )
 
Index: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_browser.py
===================================================================
--- main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_browser.py	(revision 15858)
+++ main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_browser.py	(revision 15859)
@@ -35,4 +35,5 @@
     IExtFileStore, IFileStoreNameChooser)
 from waeup.kofa.students.interfaces import IStudentsUtils
+from waeup.kofa.tests.test_authentication import SECRET
 from kofacustom.iuokada.testing import FunctionalLayer
 
@@ -46,4 +47,34 @@
         return
 
+class OfficerUITests(StudentsFullSetup):
+    # Tests for Student class views and pages
+
+    layer = FunctionalLayer
+
+    def test_lib_idcard_officer(self):
+        # Create library officer
+        self.app['users'].addUser('mrlibrary', SECRET)
+        self.app['users']['mrlibrary'].email = 'library@foo.ng'
+        self.app['users']['mrlibrary'].title = 'Carlo Pitter'
+        prmglobal = IPrincipalRoleManager(self.app)
+        prmglobal.assignRoleToPrincipal(
+            'waeup.LibraryClearanceOfficer', 'mrlibrary')
+        prmglobal.assignRoleToPrincipal(
+            'waeup.StudentsOfficer', 'mrlibrary')
+        self.browser.open(self.login_path)
+        self.browser.getControl(name="form.login").value = 'mrlibrary'
+        self.browser.getControl(name="form.password").value = SECRET
+        self.browser.getControl("Login").click()
+        self.assertMatches('...You logged in...', self.browser.contents)
+        self.browser.open(self.student_path)
+        self.assertFalse('Download Library Id Card' in self.browser.contents)
+        self.browser.getLink("Switch library access").click()
+        self.assertTrue('Library access enabled' in self.browser.contents)
+        self.browser.getLink("Download Library Id Card").click()
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
+        path = os.path.join(samples_dir(), 'lib_idcard_officer.pdf')
+        open(path, 'wb').write(self.browser.contents)
+        print "Sample PDF lib_idcard_officer.pdf written to %s" % path
 
 class StudentUITests(StudentsFullSetup):
@@ -72,2 +103,21 @@
         open(path, 'wb').write(self.browser.contents)
         print "Sample PDF course_registration_slip.pdf written to %s" % path
+
+    def test_library_idcard(self):
+        IWorkflowState(self.student).setState('returning')
+        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()
+        self.assertFalse('Library' in self.browser.contents)
+        self.student.library = True
+        self.browser.open(self.student_path)
+        self.browser.getLink("Download Library Id Card").click()
+        self.assertEqual(self.browser.headers['Status'], '200 Ok')
+        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
+        path = os.path.join(samples_dir(), 'lib_idcard_student.pdf')
+        open(path, 'wb').write(self.browser.contents)
+        print "Sample PDF lib_idcard_student.pdf written to %s" % path
+        self.assertTrue(self.student.library)
+        IWorkflowInfo(self.student).fireTransition('pay_school_fee')
+        self.assertFalse(self.student.library)
Index: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_export.py
===================================================================
--- main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_export.py	(revision 15858)
+++ main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/tests/test_export.py	(revision 15859)
@@ -56,5 +56,5 @@
             'fst_sit_type,hq2_degree,hq2_disc,hq2_matric_no,hq2_school,'
             'hq2_session,hq2_type,hq_degree,hq_disc,hq_fname,hq_matric_no,'
-            'hq_school,hq_session,hq_type,is_staff,lastname,lga,'
+            'hq_school,hq_session,hq_type,is_staff,lastname,lga,library,'
             'marit_stat,matric_number,middlename,nationality,'
             'next_kin_address,next_kin_name,next_kin_phone,next_kin_relation,'
@@ -68,5 +68,5 @@
             '"[(\'printing_craft_practice\', \'A1\')]",my clr code,1981-02-04#,,,'
             'anna@sample.com,,,,,,,,,,,,,,Anna,,,,,,"[(\'printing_craft_practice\', \'A1\')]"'
-            ',,,,,,,,,,,,,,,,Tester,,,234,M.,NG,,,,,,,,,,'
+            ',,,,,,,,,,,,,,,,Tester,,,,234,M.,NG,,,,,,,,,,'
             '"Studentroad 21\nLagos 123456\n",,+234-123-12345#,,,123,,,,,'
             '"[(\'printing_craft_practice\', \'A1\')]",,f,A111111,0,,,created,'
Index: main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/viewlets.py
===================================================================
--- main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/viewlets.py	(revision 15858)
+++ main/kofacustom.iuokada/trunk/src/kofacustom/iuokada/students/viewlets.py	(revision 15859)
@@ -23,5 +23,5 @@
 from waeup.kofa.students.interfaces import IStudent, IStudentsUtils
 from kofacustom.iuokada.students.interfaces import (
-    ICustomStudentStudyCourse, ICustomStudentStudyLevel)
+    ICustomStudentStudyCourse, ICustomStudentStudyLevel, ICustomStudent)
 from waeup.kofa.students.fileviewlets import (
     StudentFileDisplay, StudentFileUpload, StudentImage)
@@ -31,4 +31,14 @@
 
 from kofacustom.nigeria.interfaces import MessageFactory as _
+
+class SwitchLibraryAccessActionButton(ManageActionButton):
+    grok.order(7)
+    grok.context(ICustomStudent)
+    grok.view(StudentBaseDisplayFormPage)
+    grok.require('waeup.switchLibraryAccess')
+    text = _('Switch library access')
+    target = 'switch_library_access'
+    icon = 'actionicon_book.png'
+
 
 class GetMatricNumberActionButton(ManageActionButton):
@@ -50,4 +60,21 @@
             return ''
         return self.view.url(self.view.context, 'get_matric_number')
+
+# Library
+
+class LibraryIdCardActionButton(ManageActionButton):
+    grok.order(10)
+    grok.context(ICustomStudent)
+    grok.view(StudentBaseDisplayFormPage)
+    grok.require('waeup.viewStudent')
+    icon = 'actionicon_pdf.png'
+    text = _('Download Library Id Card')
+    target = 'lib_idcard.pdf'
+
+    @property
+    def target_url(self):
+        if self.context.library:
+            return self.view.url(self.view.context, self.target)
+        return
 
 # Signature
