Index: main/waeup.uniben/trunk/src/waeup/uniben/students/browser.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/students/browser.py	(revision 15342)
+++ main/waeup.uniben/trunk/src/waeup/uniben/students/browser.py	(revision 15352)
@@ -28,4 +28,5 @@
 from waeup.kofa.browser.layout import action, KofaEditFormPage, UtilityView
 from waeup.kofa.students.browser import (
+    StudentBaseEditFormPage,
     StudyLevelEditFormPage, StudyLevelDisplayFormPage,
     StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip,
@@ -56,4 +57,5 @@
 from waeup.uniben.students.interfaces import (
     ICustomStudent,
+    ICustomStudentBase,
     ICustomStudentOnlinePayment,
     ICustomStudentStudyCourse,
@@ -282,4 +284,59 @@
             self.context.student, studentview,
             omit_fields=self.omit_fields,
+            note=self.note)
+
+class ExportJHLIdCard(UtilityView, grok.View):
+    """Deliver a an id card for the John Harris Library.
+    """
+    grok.context(ICustomStudent)
+    grok.name('jhl_idcard.pdf')
+    grok.require('waeup.viewStudent')
+    prefix = 'form'
+
+    label = u"John Harris Library Reader's Ticket"
+
+    omit_fields = (
+        'suspended', 'email',
+        'adm_code', 'suspended_comment',
+        'date_of_birth','reg_number',
+        'current_mode', 'certificate',
+        'entry_session',
+        'flash_notice')
+
+    form_fields = []
+
+    def _signatures(self):
+        return ([(
+            'Current HD<br /> D. R. (Exams & Records)<br /> '
+            'For: Registrar')],)
+
+    def _sigsInFooter(self):
+        return (_("Date, Reader's Signature"),
+                _("Date, Circulation Librarian's Signature"),
+                )
+
+    @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 <b>John Harris Library, University of Benin</b>.
+ The card is not transferable. A replacement fee is charged for a loss,
+ mutilation or otherwise. If found, please, return to John Harris Library,
+ University of Benin, Benin City.
+</font>
+
+"""
+        return
+
+    def render(self):
+        studentview = StudentBasePDFFormPage(self.context.student,
+            self.request, self.omit_fields)
+        students_utils = getUtility(IStudentsUtils)
+        return students_utils.renderPDF(
+            self, 'jhl_idcard',
+            self.context.student, studentview,
+            omit_fields=self.omit_fields,
+            sigs_in_footer=self._sigsInFooter(),
             note=self.note)
 
@@ -595,5 +652,4 @@
     """Deliver a PDF slip of the context.
     """
-
     omit_fields = ('password', 'suspended', 'suspended_comment',
         'phone', 'adm_code', 'email', 'date_of_birth', 'flash_notice')
@@ -613,2 +669,9 @@
     """
     with_hostel_selection = True
+
+class CustomStudentBaseEditFormPage(StudentBaseEditFormPage):
+    """ View to edit student base data
+    """
+    form_fields = grok.AutoFields(ICustomStudentBase).select(
+        'email', 'phone')
+    form_fields['email'].field.required = True
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 15342)
+++ main/waeup.uniben/trunk/src/waeup/uniben/students/tests/test_browser.py	(revision 15352)
@@ -213,4 +213,16 @@
         self.browser.open(self.student_path)
         self.assertFalse('examination schedule slip' in self.browser.contents)
+
+    def test_jhl_idcard(self):
+        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.browser.getLink("Download JHL 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(), 'jhl_idcard.pdf')
+        open(path, 'wb').write(self.browser.contents)
+        print "Sample PDF jhl_idcard.pdf written to %s" % path
 
     def test_jupeb_result_slip(self):
Index: main/waeup.uniben/trunk/src/waeup/uniben/students/viewlets.py
===================================================================
--- main/waeup.uniben/trunk/src/waeup/uniben/students/viewlets.py	(revision 15342)
+++ main/waeup.uniben/trunk/src/waeup/uniben/students/viewlets.py	(revision 15352)
@@ -111,4 +111,17 @@
         return False
 
+class JHLIdCardActionButton(ManageActionButton):
+    grok.order(10)
+    grok.context(ICustomStudent)
+    grok.view(StudentBaseDisplayFormPage)
+    grok.require('waeup.viewStudent')
+    icon = 'actionicon_pdf.png'
+    text = _('Download JHL Id Card')
+    target = 'jhl_idcard.pdf'
+
+    @property
+    def target_url(self):
+        return self.view.url(self.view.context, self.target)
+
 class JUPEBResultSlipActionButton(ManageActionButton):
     grok.order(11)
