## $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')