## $Id: browser.py 17884 2024-08-10 21:31:06Z henrik $ ## ## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## import grok import os from zope.i18n import translate from zope.schema.interfaces import ConstraintNotSatisfied from zope.component import getUtility from zope.security import checkPermission from zope.formlib.textwidgets import BytesDisplayWidget from hurry.workflow.interfaces import IWorkflowInfo from waeup.kofa.interfaces import ( REQUESTED, ADMITTED, CLEARANCE, REQUESTED, CLEARED, IExtFileStore, IKofaUtils, academic_sessions_vocab) from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget from waeup.kofa.browser.layout import ( action, jsaction, UtilityView, KofaEditFormPage) from waeup.kofa.students.browser import ( StudyLevelEditFormPage, StudyLevelDisplayFormPage, StudentBasePDFFormPage, ExportPDFCourseRegistrationSlip, CourseTicketDisplayFormPage, StudentTriggerTransitionFormPage, StartClearancePage, BalancePaymentAddFormPage, ExportPDFAdmissionSlip, ExportPDFPersonalDataSlip, PaymentsManageFormPage, msave, emit_lock_message) from waeup.kofa.students.interfaces import ( IStudentsUtils, ICourseTicket, IStudent) from waeup.kofa.students.vocabularies import StudyLevelSource from waeup.kofa.students.workflow import FORBIDDEN_POSTGRAD_TRANS from kofacustom.nigeria.students.browser import ( NigeriaOnlinePaymentDisplayFormPage, NigeriaStudentBaseDisplayFormPage, NigeriaStudentBaseManageFormPage, NigeriaStudentClearanceEditFormPage, NigeriaOnlinePaymentAddFormPage, NigeriaExportPDFPaymentSlip, NigeriaExportPDFClearanceSlip, NigeriaExportPDFCourseRegistrationSlip, NigeriaStudentBaseEditFormPage, NigeriaBedTicketAddPage, NigeriaAccommodationManageFormPage, NigeriaAccommodationDisplayFormPage, NigeriaStudentPersonalManageFormPage, NigeriaStudentPersonalEditFormPage, NigeriaStudentPersonalDisplayFormPage ) from kofacustom.iuokada.students.interfaces import ( ICustomStudentOnlinePayment, ICustomStudentStudyCourse, ICustomStudentStudyLevel, ICustomStudentBase, ICustomStudent, ICustomStudentPersonal, ICustomStudentPersonalEdit) from kofacustom.iuokada.interfaces import MessageFactory as _ class CustomStudentBaseDisplayFormPage(NigeriaStudentBaseDisplayFormPage): """ Page to display student base data """ form_fields = grok.AutoFields(ICustomStudentBase).omit( 'password', 'suspended', 'suspended_comment', 'flash_notice', 'financially_cleared_by', 'financial_clearance_date', 'finally_cleared_by', 'final_clearance_date') class CustomStudentBaseManageFormPage(NigeriaStudentBaseManageFormPage): """ View to manage student base data """ form_fields = grok.AutoFields(ICustomStudentBase).omit( 'student_id', 'adm_code', 'suspended', 'financially_cleared_by', 'financial_clearance_date', 'finally_cleared_by', 'final_clearance_date') class StudentBaseEditFormPage(NigeriaStudentBaseEditFormPage): """ View to edit student base data """ @property def form_fields(self): form_fields = grok.AutoFields(ICustomStudentBase).select( 'email', 'email2', 'parents_email', 'phone',) if not self.context.state in (ADMITTED, CLEARANCE): form_fields['parents_email'].for_display = True return form_fields class CustomExportPDFCourseRegistrationSlip( NigeriaExportPDFCourseRegistrationSlip): """Deliver a PDF slip of the context. """ def _signatures(self): return ( ['Student Signature'], ['HoD / Course Adviser Signature'], ['College Officer Signature'], ['Dean Signature'] ) #def _sigsInFooter(self): # return (_('Student'), # _('HoD / Course Adviser'), # _('College Officer'), # _('Dean'), # ) # return () class CustomStudentPersonalDisplayFormPage(NigeriaStudentPersonalDisplayFormPage): """ Page to display student personal data """ form_fields = grok.AutoFields(ICustomStudentPersonal) form_fields['perm_address'].custom_widget = BytesDisplayWidget form_fields['postal_address'].custom_widget = BytesDisplayWidget form_fields['hostel_address'].custom_widget = BytesDisplayWidget form_fields['father_address'].custom_widget = BytesDisplayWidget form_fields['mother_address'].custom_widget = BytesDisplayWidget form_fields['guardian_address'].custom_widget = BytesDisplayWidget form_fields[ 'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le') class CustomStudentPersonalEditFormPage(NigeriaStudentPersonalEditFormPage): """ Page to edit personal data """ form_fields = grok.AutoFields(ICustomStudentPersonalEdit).omit( 'personal_updated') def update(self): #if not self.context.is_fresh: # self.flash('Not allowed.', type="danger") # self.redirect(self.url(self.context)) # return if not self.context.minimumStudentPayments(): self.flash('Please make 40% of your tution fee payments first.', type="warning") self.redirect(self.url(self.context, 'view_personal')) return super(CustomStudentPersonalEditFormPage, self).update() return class CustomStudentPersonalManageFormPage(NigeriaStudentPersonalManageFormPage): """ Page to manage personal data """ form_fields = grok.AutoFields(ICustomStudentPersonal) form_fields['personal_updated'].for_display = True form_fields[ 'personal_updated'].custom_widget = FriendlyDatetimeDisplayWidget('le') class CustomExportPDFPersonalDataSlip(ExportPDFPersonalDataSlip): """Deliver a PDF base and personal data slip. """ grok.name('course_registration_clearance.pdf') omit_fields = ( 'phone', 'email', 'suspended', 'adm_code', 'suspended_comment', 'current_level', 'flash_notice', 'entry_session', 'parents_email') form_fields = grok.AutoFields(ICustomStudentPersonal) def _signatures(self): return ([('I certify that the above named student has satisfied the financial requirements for registration.', 'Name and Signature of Bursary Staff', '

')], [('I certify that the credentials of the student have been screened by me and the student is hereby cleared.', 'Name and Signature of Registry Staff', '

')], [('I certify that the above named student has registered with the Library.', 'Name and Signature of Library Staff', '

')], [('I certify that the above named student has been registered with the college. ', 'Name and Signature of College Officer', '

')], [('I certify that the above named student has completed his/her ICT registration. ', 'Name and Signature of ICT Staff', '

')], [('Eligibility/Congratulation Station', 'Name and Signature of Registrar', '')], ) @property def tabletitle(self): portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE tabletitle = [] session = self.context.student.current_session tabletitle.append('_PB_Successful %s/%s Session Payments' %(session, session+1)) return tabletitle def render(self): if not self.context.minimumStudentPayments(): self.redirect(self.url(self.context)) return studentview = StudentBasePDFFormPage(self.context.student, self.request, self.omit_fields) students_utils = getUtility(IStudentsUtils) portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE P_ID = translate(_('Payment Id'), 'waeup.kofa', target_language=portal_language) #CD = translate(_('Creation Date'), 'waeup.kofa', target_language=portal_language) PD = translate(_('Payment Date'), 'waeup.kofa', target_language=portal_language) CAT = translate(_('Payment Category'), 'waeup.kofa', target_language=portal_language) ITEM = translate(_('Payment Item'), 'waeup.kofa', target_language=portal_language) AMT = translate(_('Amount (Naira)'), 'waeup.kofa', target_language=portal_language) SSS = translate(_('Payment Session'), 'waeup.kofa', target_language=portal_language) tabledata = [] tableheader = [] tabledata.append(sorted( [value for value in self.context['payments'].values() if value.p_state in ('paid', 'waived', 'scholarship') and value.p_session >= value.student.current_session], key=lambda value: value.p_session)) tableheader.append([(P_ID,'p_id', 4.2), #(CD,'creation_date', 3), (PD,'formatted_p_date', 3), (CAT,'category', 3), (ITEM, 'p_item', 3), (AMT, 'amount_auth', 2), (SSS, 'p_session', 2), ]) #watermark_path = os.path.join( # os.path.dirname(__file__), 'static', 'watermark.pdf') #watermark = open(watermark_path, 'rb') #file_path = os.path.join( # os.path.dirname(__file__), 'static', 'biodataPage2.pdf') #file = open(file_path, 'rb') #mergefiles = [file,] return students_utils.renderPDF( self, 'course_registration_clearance.pdf', self.context.student, studentview, omit_fields=self.omit_fields, signatures=self._signatures(), tableheader=tableheader, tabledata=tabledata, pagebreak=True, # mergefiles=mergefiles, # watermark=watermark ) class CustomAccommodationDisplayFormPage(NigeriaAccommodationDisplayFormPage): """ Page to view bed tickets. """ with_hostel_selection = True class CustomAccommodationManageFormPage(NigeriaAccommodationManageFormPage): """ Page to manage bed tickets. This manage form page is for both students and students officers. """ with_hostel_selection = True class CustomBedTicketAddPage(NigeriaBedTicketAddPage): """ Page to add a bed ticket """ with_ac = False with_bedselection = True class CustomPaymentsManageFormPage(PaymentsManageFormPage): """ Page to manage the student payments. This manage form page is for both students and students officers. IUOkada does not allow students to remove any payment ticket. """ grok.template('paymentsmanagepage') def _schoolfee_payments_made(self): cs = self.context.student.current_session es = self.context.student.entry_session SF_PAYMENTS = ('schoolfee', 'schoolfee40', 'secondinstal', 'clearance') sf_paid = dict() try: certificate = self.context.student['studycourse'].certificate except (AttributeError, TypeError): return sf_paid, 0 session = es # Initiliaze sf_paid dict with items # session: [school fee in session, amount paid in session, amount due] sf_paid[session] = [getattr(certificate, 'school_fee_1', 0.0), 0.0, 0.0] while session < cs + 1: session += 1 sf_paid[session]= [getattr(certificate, 'school_fee_2', 0.0), 0.0, 0.0] sessions = sf_paid.keys() brought_fwd = 0.0 # Collect all payments made or brought forward for ticket in self.context.values(): amt = ticket.net_amt if not amt: amt = ticket.amount_auth if ticket.p_category in SF_PAYMENTS and \ ticket.p_state == 'paid' and \ ticket.p_session in sessions: sf_paid[ticket.p_session][1] += amt if ticket.p_state != 'paid' and\ ticket.p_category == 'brought_fwd': brought_fwd += ticket.amount_auth # Calculate due, first for the entry session # amount due in session = brought forward from previous sessions + school fees in session - amount paid in session session = es try: sf_paid[session][2] = brought_fwd + sf_paid[session][0] - sf_paid[session][1] except TypeError: return dict(), brought_fwd while session < cs + 1: session += 1 # amount due in session = brought forward from previous session + school fee in session - amount paid in session sf_paid[session][2] = sf_paid[session-1][2] + sf_paid[session][0] - sf_paid[session][1] return sorted(sf_paid.items(), key=lambda value: value[0]), brought_fwd #def update(self): # super(CustomPaymentsManageFormPage, self).update() # self.sfp_made = self._schoolfee_payments_made() # return @property def manage_payments_allowed(self): return checkPermission('waeup.manageStudent', self.context) class StudentGetMatricNumberPage(UtilityView, grok.View): """ Construct and set the matriculation number. """ grok.context(IStudent) grok.name('get_matric_number') grok.require('waeup.manageStudent') def update(self): students_utils = getUtility(IStudentsUtils) msg, mnumber = students_utils.setMatricNumber(self.context) if msg: self.flash(msg, type="danger") else: self.flash(_('Matriculation number %s assigned.' % mnumber)) self.context.writeLogMessage(self, '%s assigned' % mnumber) self.redirect(self.url(self.context)) return 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 """



This is to certify that the bearer whose photograph and other details appear overleaf is a registered user of the University Library. 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. """ 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) class CustomStartClearancePage(StartClearancePage): with_ac = False class CustomBalancePaymentAddFormPage(BalancePaymentAddFormPage): grok.require('waeup.payStudent') from kofacustom.iuokada.students.admission_letter_ug import ( ADML_UG_1, ADML_UG_2, ADML_UG_3, ADML_UG_2_MEDICAL, ADML_UG_2_PHARMACY, BASIC_MEDICAL_ONLY, BASIC_PHARMACY_ONLY) from kofacustom.iuokada.students.admission_letter_pg import ADML_PG from kofacustom.iuokada.students.admission_letter_pt import ADML_PT from kofacustom.iuokada.students.admission_letter_jupeb import ADML_JUPEB from kofacustom.iuokada.students.admission_letter_cdl import ADML_CDL class CustomExportPDFAdmissionSlip(ExportPDFAdmissionSlip): """Deliver a PDF Admission slip. """ omit_fields = ('date_of_birth', #'current_level', #'current_mode', #'entry_session' ) @property def session(self): return academic_sessions_vocab.getTerm( self.context.entry_session).title @property def level(self): studylevelsource = StudyLevelSource() return studylevelsource.factory.getTitle( self.context['studycourse'].certificate, self.context.current_level) @property def label(self): return 'OFFER OF PROVISIONAL ADMISSION \nFOR %s SESSION' % self.session @property def pre_text_ug(self): return ( 'Following your performance in the screening exercise ' 'for the %s academic session, I am pleased to inform ' 'you that you have been offered provisional admission into the ' 'Igbinedion University, Okada as follows:' % self.session) @property def pre_text_pg(self): return ( 'I am pleased to inform you that your application for admission' ' into the Igbinedion University, Okada was successful. You have' ' been admitted as follows:') @property def pre_text_cdl(self): return ( 'I am pleased to inform you that you have been offered provisional' ' admission into the Igbinedion University, ' 'Centre for Distance Learning as follows:') def render(self): students_utils = getUtility(IStudentsUtils) watermark_path = os.path.join( os.path.dirname(__file__), 'static', 'watermark.pdf') watermark = open(watermark_path, 'rb') if grok.getSite().__name__ == 'iuokada-cdl': return students_utils.renderPDFAdmissionLetter(self, self.context.student, omit_fields=self.omit_fields, pre_text=self.pre_text_cdl, post_text=ADML_CDL, watermark=watermark) if self.context.is_jupeb: return students_utils.renderPDFAdmissionLetter(self, self.context.student, omit_fields=self.omit_fields, pre_text=self.pre_text_ug, post_text=ADML_JUPEB, watermark=watermark) if self.context.current_mode.endswith('_pt'): return students_utils.renderPDFAdmissionLetter(self, self.context.student, omit_fields=self.omit_fields, pre_text=self.pre_text_ug, post_text=ADML_PT, watermark=watermark) if self.context.is_postgrad: file_path = os.path.join( os.path.dirname(__file__), 'static', 'admission_letter_pg.pdf') file = open(file_path, 'rb') mergefiles = [file,] return students_utils.renderPDFAdmissionLetter(self, self.context.student, omit_fields=self.omit_fields, pre_text=self.pre_text_pg, post_text=ADML_PG, mergefiles=mergefiles, watermark=watermark) file_path = os.path.join( os.path.dirname(__file__), 'static', 'admission_letter_ug.pdf') file = open(file_path, 'rb') mergefiles = [file,] if self.context.certcode in ('BBMS', 'MBBS') and self.context.current_level == 100: # Changed on 18/07/24 #post_text = BASIC_MEDICAL_ONLY + ADML_UG_1 + ADML_UG_2_MEDICAL + ADML_UG_3 post_text = ADML_UG_1 + ADML_UG_2_MEDICAL + ADML_UG_3 elif self.context.certcode in ('BPHARM',) and self.context.current_level == 100: # Changed on 18/07/24 #post_text = BASIC_PHARMACY_ONLY + ADML_UG_1 + ADML_UG_2_MEDICAL + ADML_UG_3 post_text = ADML_UG_1 + ADML_UG_2_MEDICAL + ADML_UG_3 else: post_text = ADML_UG_1 + ADML_UG_2 + ADML_UG_3 return students_utils.renderPDFAdmissionLetter(self, self.context.student, omit_fields=self.omit_fields, pre_text=self.pre_text_ug, post_text=post_text, mergefiles=mergefiles, watermark=watermark) class CustomOnlinePaymentDisplayFormPage(NigeriaOnlinePaymentDisplayFormPage): """ Page to view an online payment ticket. We do not omit provider_amt. """ form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit( 'gateway_amt', 'thirdparty_amt', 'p_item','p_combi', 'provider_amt') form_fields[ 'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le') form_fields[ 'payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le') class CustomExportPDFPaymentSlip(NigeriaExportPDFPaymentSlip): """Deliver a PDF slip of the context. We do not omit provider_amt. """ form_fields = grok.AutoFields(ICustomStudentOnlinePayment).omit( 'gateway_amt', 'thirdparty_amt', 'p_item', 'p_split_data','p_combi', 'provider_amt') form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le') form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')